Course Contents

  1. 2022.12.07: Introduction: About the course [lead by TK]
    • An introduction to open and public data, and data science
  2. 2022-12-14: Exploratory Data Analysis (EDA) 1 [lead by hs]
    • R Basics with RStudio and/or RStudio.cloud; Toy Data
  3. 2022-12-21: Exploratory Data Analysis (EDA) 2 [lead by hs]
    • R Markdown, tidyverse I: dplyr; gapminder
  4. 2023-01-11: Exploratory Data Analysis (EDA) 3 [lead by hs]
    • tidyverseII: readr, ggplot2; Public Data, WDI, WIR, etc
  5. 2023-01-18: Exploratory Data Analysis (EDA) 4 [lead by hs]
    • tidyverse III: tidyr, etc.; WDI, WIR, etc
  6. 2023-01-25: Exploratory Data Analysis (EDA) 5 [lead by hs]
    • tidyverse IV; WDI, WIR, etc
  7. 2023-02-01: Introduction to PPDAC
    • Problem-Plan-Data-Analysis-Conclusion Cycle: [lead by TK]
  8. 2023-02-08: Model building I [lead by TK]
    • Collecting and visualizing data and Introduction to WDI
      (World Development Indicators by World Bank)
  9. 2023-02-15: Model building II [lead by TK]
    • Analyzing data and communications
  10. 2023-02-22: Project Presentation

1 Exploratory Data Analysis (EDA) I

2 Exploratory Data Analysis II

3 Exploratory Data Analysis III

4 Exploratory Data Analysis (EDA) IV

4.1 Tidy Data

4.1.1 Reviews and Previews

4.1.2 Example: World Inequility Report - WIR2022

library(tidyverse)
library(readxl)
url_summary <- "https://wir2022.wid.world/www-site/uploads/2022/03/WIR2022TablesFigures-Summary.xlsx"
download.file(url = url_summary, destfile = "data/WIR2022s.xlsx") 
excel_sheets("data/WIR2022s.xlsx")
 [1] "Index"     "F1"        "F2"        "F3"        "F4"        "F5."       "F6"       
 [8] "F7"        "F8"        "F9"        "F10"       "F11"       "F12"       "F13"      
[15] "F14"       "F15"       "T1"        "data-F1"   "data-F2"   "data-F3"   "data-F4"  
[22] "data-F5"   "data-F6"   "data-F7"   "data-F8"   "data-F9"   "data-F10"  "data-F11" 
[29] "data-F12"  "data-F13." "data-F14." "data-F15" 

4.1.3 F1: Global income and wealth inequality, 2021

df_f1 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F1")
df_f1

df_f1_rev %>%
  ggplot(aes(x = cat, y = value, fill = group)) +
  geom_col(position = "dodge")


4.1.4 References of tidyr

4.1.4.1 RStudio Primers: See References in Moodle at the bottom

Tidy Your Data

  • Reshape Data
  • Separate and Unite Columns
  • Join Data Sets

4.1.5 Variables, values, and observations: Definitions

  • A variable is a quantity, quality, or property that you can measure.
  • A value is the state of a variable when you measure it. The value of a variable may change from measurement to measurement.
  • An observation or case is a set of measurements made under similar conditions (you usually make all of the measurements in an observation at the same time and on the same object). An observation will contain several values, each associated with a different variable. I’ll sometimes refer to an observation as a case or data point.
  • Tabular data is a table of values, each associated with a variable and an observation. Tabular data is tidy if each value is placed in its own cell, each variable in its own column, and each observation in its own row.
  • So far, all of the data that you’ve seen has been tidy. In real-life, most data isn’t tidy, so we’ll come back to these ideas again in Data Wrangling.

4.1.6 Tidy Data

“Data comes in many formats, but R prefers just one: tidy data.” — Garrett Grolemund

Data can come in a variety of formats, but one format is easier to use in R than the others. This format is known as tidy data. A data set is tidy if:

  1. Each variable is in its own column
  2. Each observation is in its own row
  3. Each value is in its own cell (this follows from #1 and #2)

“Tidy data sets are all alike; but every messy data set is messy in its own way.” — Hadley Wickham

“all happy families are all alike; each unhappy family is unhappy in its own way” - Tolstoy’s Anna Karenina


4.1.7 tidyr Basics

  1. Each variable is in its own column
  2. Each observation is in its own row

4.1.8 Pivot data from wide to long: pivot_longer()

pivot_longer(data, cols = <columns to pivot into longer format>,
  names_to = <name of the new character column>, # e.g. "group", "category", "class"
  values_to = <name of the column the values of cells go to>) # e.g. "value", "n"
df_f1
(df_f1_rev <- df_f1 %>% pivot_longer(-1, names_to = "group", values_to = "value"))

df_f1_rev %>% 
  ggplot(aes(x = ...1, y = value, fill = group)) +
  geom_col(position = "dodge")


df_f1_rev %>% filter(group != "Top 1%") %>%
  ggplot() +
  geom_col(aes(x = ...1, y = value, fill = group), position = "dodge") +
  geom_text(aes(x = ...1, y = value, group = group, 
            label = scales::label_percent(accuracy=1)(value)), 
            position = position_dodge(width = 0.9)) + 
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Figure 1. Global income and wealth inequality, 2021",
       x = "", y = "Share of total income or wealth", fill = "")

Interpretation: The global bottom 50% captures 8.5% of total income measured at Purchasing Power Parity (PPP). The global bottom 50% owns 2% of wealth (at Purchasing Power Parity). The global top 10% owns 76% of total Household wealth and captures 52% of total income in 2021. Note that top wealth holders are not necessarily top income holders. Incomes are measured after the operation of pension and unemployment systems and before taxes and transfers.
Sources and series: wir2022.wid.world/methodology.


4.1.9 F2: The poorest half lags behind: Bottom 50%, middle 40% and top 10% income shares across the world in 2021

df_f2 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F2")
df_f2

df_f2 %>% pivot_longer(cols = 3:5, names_to = "group", values_to = "value")

df_f2 %>% pivot_longer(cols = 3:5, names_to = "group", values_to = "value") %>%
  ggplot(aes(x = iso, y = value, fill = group)) +
  geom_col(position = "dodge")


4.1.10 Pivot data from long to wide:

pivot_wider() In Console: vignette(“pivot”)

pivot_wider(data, 
  names_from = <name of the column (or columns) to get the name of the output column>,
  values_from = <name of the column to get the value of the output>) 

pivot_wider(data, names_from = group, values_from = value) 

4.1.11 Practice: F4 and F13

F4 and F13 are similar. Please use pivot_longer to tidy the data and create charts.

4.1.11.1 Done Last Week

  • F12: Female share in global labor incomes, 1990-2020
  • F14: Global carbon inequality, 2019. Group contribution to world emissions (%)

4.1.12 F3: Top 10/Bottom 50 income gaps across the world, 2021

df_f3 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F3")
df_f3

4.1.13 F3: Top 10/Bottom 50 income gaps across the world, 2021 - Original


  • To 10 / Bottom 50 ratio has 5 classes: 5-12, 12-13, 13-16, 16-19, 19-140
df_f3$T10B50 %>% summary()
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  5.394  10.958  15.676  17.635  19.838 139.591 

df_f3 %>% ggplot() + geom_histogram(aes(T10B50))


df_f3 %>% arrange(desc(T10B50))

df_f3 %>% 
  mutate(`Top 10 Bottom 50 Ratio` = cut(T10B50,breaks = c(5, 12, 13, 16, 19,140), 
                                        include.lowest = FALSE)) 

world_map <- map_data("world")
df_f3 %>% mutate(`Top 10 Bottom 50 Ratio` = cut(T10B50,breaks = c(5, 12, 13, 16, 19,140), 
                                        include.lowest = FALSE)) %>%
  ggplot(aes(map_id = Country)) + 
  geom_map(aes(fill = `Top 10 Bottom 50 Ratio`), map = world_map) + 
  expand_limits(x = world_map$long, y = world_map$lat)


world_map_wir <- world_map
world_map_wir$region[
  world_map_wir$region=="Democratic Republic of the Congo"]<-"DR Congo"
world_map_wir$region[world_map_wir$region=="Republic of Congo"]<-"Congo"
world_map_wir$region[world_map_wir$region=="Ivory Coast"]<-"Cote dIvoire"
world_map_wir$region[world_map_wir$region=="Vietnam"]<-"Viet Nam"
world_map_wir$region[world_map_wir$region=="Russia"]<-"Russian Federation"
world_map_wir$region[world_map_wir$region=="South Korea"]<-"Korea"
world_map_wir$region[world_map_wir$region=="UK"]<-"United Kingdom"
world_map_wir$region[world_map_wir$region=="Brunei"]<-"Brunei Darussalam"
world_map_wir$region[world_map_wir$region=="Laos"]<-"Lao PDR"
world_map_wir$region[world_map_wir$region=="Cote dIvoire"]<-"Cote d'Ivoire"
world_map_wir$region[world_map_wir$region=="Cape Verde"]<- "Cabo Verde"
world_map_wir$region[world_map_wir$region=="Syria"]<- "Syrian Arab Republic"
world_map_wir$region[world_map_wir$region=="Trinidad"]<- "Trinidad and Tobago"
world_map_wir$region[world_map_wir$region=="Tobago"]<- "Trinidad and Tobago"

df_f3 %>% mutate(`Top 10 Bottom 50 Ratio` = 
    cut(T10B50, breaks = c(5, 12, 13, 16, 19,140), include.lowest = FALSE)) %>%
  ggplot(aes(map_id = Country)) + 
  geom_map(aes(fill = `Top 10 Bottom 50 Ratio`), 
    map = world_map_wir) + 
    expand_limits(x = world_map_wir$long, y = world_map_wir$lat)


df_f3 %>% mutate(`Top 10 Bottom 50 Ratio` = 
    cut(T10B50,breaks = c(5, 12, 13, 16, 19,140), include.lowest = FALSE)) %>%
  ggplot(aes(map_id = Country)) + geom_map(aes(fill = `Top 10 Bottom 50 Ratio`), 
    map = world_map_wir) + expand_limits(x = world_map_wir$long, y = world_map_wir$lat) + 
  coord_map("orthographic", orientation = c(25, 60, 0))


df_f3 %>% mutate(`Top 10 Bottom 50 Ratio` = 
  cut(T10B50,breaks = c(5, 12, 13, 16, 19,140), include.lowest = FALSE)) %>%
  ggplot(aes(map_id = Country)) + geom_map(aes(fill = `Top 10 Bottom 50 Ratio`), 
    map = world_map_wir) + expand_limits(x = world_map_wir$long, y = world_map_wir$lat) + 
  coord_map("orthographic", orientation = c(15, -80, 0))


df_f3 %>% mutate(`Top 10 Bottom 50 Ratio` = 
  cut(T10B50,breaks = c(5, 12, 13, 16, 19,140), include.lowest = FALSE)) %>%
  ggplot(aes(map_id = Country)) + geom_map(aes(fill = `Top 10 Bottom 50 Ratio`), 
    map = world_map_wir) + 
  expand_limits(x = world_map_wir$long, y = world_map_wir$lat)


df_f3 %>% 
  mutate(`Top 10 Bottom 50 Ratio` = 
        cut(T10B50,breaks = c(5, 12, 13, 16, 19,140), include.lowest = FALSE)) %>%
  ggplot(aes(map_id = Country)) + 
  geom_map(aes(fill = `Top 10 Bottom 50 Ratio`), map = world_map_wir) + 
  expand_limits(x = world_map_wir$long, y = world_map_wir$lat)  + 
  labs(title = "Figure 3. Top 10/Bottom 50 income gaps across the world, 2021",
       x = "", y = "", fill = "Top 10/Bottom 50 ratio") +
  theme(legend.position="bottom", 
        axis.text.x=element_blank(), axis.ticks.x=element_blank(),
        axis.text.y=element_blank(), axis.ticks.y=element_blank()) + 
  scale_fill_brewer(palette='YlOrRd')


df_f3 %>% anti_join(world_map_wir, by = c("Country" = "region"))

Filtering joins

  • anti_join(x,y, ...): return all rows from x without a match in y.
  • semi_join(x,y, ...): return all rows from x with a match in y.

Check dplyr cheat sheet, and Posit Primers Tidy Data.


4.1.14 Remaining Charts

  • F5: Global income inequality: T10/B50 ratio, 1820-2020 - fit curve

  • F9: Average annual wealth growth rate, 1995-2021 - fit curve + alpha

  • F7: Global income inequality, 1820-2020 - pivot + fit curve

  • F10: The share of wealth owned by the global 0.1% and billionaires, 2021 - pivot + fit curve

  • F6: Global income inequality: Between vs. Within country inequality (Theil index), 1820-2020 - pivot + area

  • F11: Top 1% vs bottom 50% wealth shares in Western Europe and the US, 1910-2020 - pivot name_sep + fit curve

  • F8: The rise of private versus the decline of public wealth in rich countries, 1970-2020 - rename + pivot + pivot + fit curve

  • F15: Per capita emissions acriss the world, 2019 - add row names + dodge


4.1.15 F5: Global income inequality: T10/B50 ratio, 1820-2020

(df_f5 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F5"))

df_f5 %>% ggplot(aes(x = y, y = t10b50)) + geom_line() + geom_smooth(span=0.25, se=FALSE)


4.1.16 F9: Average annual wealth growth rate, 1995-2021 - fit curve + alpha

df_f9 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F9"); df_f9

df_f9 %>% 
  ggplot(aes(x = p, y = `Wealth growth 1995-2021`)) + geom_smooth(span = 0.30, se = FALSE)


4.1.17 F7: Global income inequality, 1820-2020 - pivot + fit curve

df_f7 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F7"); df_f7

df_f7 %>% 
  pivot_longer(cols = 2:4, names_to = "type", values_to = "value") %>%
  ggplot(aes(x = y, y = value, color = type)) +
  stat_smooth(formula = y~x, method = "loess", span = 0.25, se = FALSE)


4.1.18 F10: The share of wealth owned by the global 0.1% and billionaires, 2021 - pivot + fit curve

df_f10 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F10"); df_f10
New names:

df_f10 %>% 
  select(year, "Global Billionaire Wealth" = bn_hhweal, "Top 0.01%" = top0.1_hhweal) %>%
  pivot_longer(!year, names_to = "group",".value", values_to = "value")

df_f10 %>% 
  select(year, "Global Billionaire Wealth" = bn_hhweal, "Top 0.01%" = top0.1_hhweal) %>%
  pivot_longer(!year, names_to = "group",".value", values_to = "value") %>%
  ggplot() +
  stat_smooth(aes(x = year, y = value, color = group), formula = y~x, method = "loess", span = 0.25, se = FALSE)


4.1.19 F6: Global income inequality: Between vs. Within country inequality (Theil index), 1820-2020 - pivot + area

df_f6 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F6"); df_f6
New names:

df_f6 %>% select(year = "...1", 2:3) %>%
  pivot_longer(cols = 2:3, names_to = "type", values_to = "value") %>%
  mutate(types = factor(type, 
      levels = c("Within-country inequality", "Between-country inequality"))) %>%
  ggplot(aes(x = year, y = value, fill = types)) +
  geom_area() +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  scale_x_continuous(breaks = round(seq(1820, 2020, by = 20),1)) + 
  scale_fill_manual(values=rev(scales::hue_pal()(2)), 
      labels = function(x) str_wrap(x, width = 15)) +
  labs(title = "Figure 6. Global income inequality: 
       \nBetween vs. within country inequality (Theil index), 1820-2020",
       x = "", y = "Share of global inequality (% of total Theil index)", fill = "") + 
  annotate("text", x = 1850, y = 0.28, 
      label = stringr::str_wrap("1820: Between country inequality represents 11% 
                                of global inequality", width = 20), size = 3) + 
  annotate("text", x = 1980, y = 0.70, 
      label = stringr::str_wrap("1980: Between country inequality represents 57% 
                                of global inequality", width = 20), size = 3) +
  annotate("text", x = 1990, y = 0.30, 
      label = stringr::str_wrap("2020: Between country inequality represents 32% 
                                of global inequality", width = 20), size = 3)


4.1.20 F11: Top 1% vs bottom 50% wealth shares in Western Europe and the US, 1910-2020 - pivot name_sep + fit curve

df_f11 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F11"); df_f11

df_f11 %>% 
  rename(!year, US_bot50 = USbot50, US_top1 = UStop1, 
         EU_bot50 = EUbot50, EU_top1 = EUtop1) %>%
  pivot_longer(!year, names_to = c("group",".value"), names_sep = "_") %>%
  pivot_longer(3:4, names_to = "type", values_to = "value") %>%
  ggplot() +
  stat_smooth(aes(x = year, y = value, color = group, linetype = type), 
              span = 0.25, se = FALSE) +
  scale_x_continuous(breaks = round(seq(1910, 2020, by = 10),1)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Figure 11. Top 1% vs bottom 50% wealth shares 
       \n in Western Europe and the US, 1910-2020", 
       x = "", y = "Share of total personal wealth (%)", color = "", linetype = "") +
  scale_linetype_manual(values = c("dotted","solid")) +
  annotate("text", x = 2000, y = 0.50, 
      label = stringr::str_wrap("Wealth inequality has been rising at 
        different speeds after a historical decline. The bottom 50% has always been 
                                extremely low.", width = 30), size = 3)

4.1.20.1 Step 1.

df_f11 %>% rename(!year, US_bot50 = USbot50, US_top1 = UStop1, 
                  EU_bot50 = EUbot50, EU_top1 = EUtop1) 

4.1.20.2 Step 2.

df_f11 %>% 
  rename(!year, US_bot50 = USbot50, US_top1 = UStop1, 
         EU_bot50 = EUbot50, EU_top1 = EUtop1) %>%
  pivot_longer(!year, names_to = c("group",".value"), names_sep = "_")

4.1.20.3 Step 2.


4.1.20.4 Step 3.

df_f11 %>% 
  rename(!year, US_bot50 = USbot50, US_top1 = UStop1, 
         EU_bot50 = EUbot50, EU_top1 = EUtop1) %>%
  pivot_longer(!year, names_to = c("group",".value"), 
               names_sep = "_") %>%
  pivot_longer(3:4, names_to = "type", values_to = "value") 

4.1.20.5 Step 3.



4.1.21 F8: The rise of private versus the decline of public wealth in rich countries, 1970-2020 - rename + pivot + pivot + fit curve

df_f8 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F8"); df_f8

df_f8 %>% 
  select(year, Germany_public = Germany, Germany_private = 'Germany (private)', 
         Spain_public = Spain, Spain_private = 'Spain (private)', 
         France_public = France, France_private = 'France (private)', 
         UK_public  = UK, UK_private = 'UK (private)', 
         Japan_public = Japan, Japan_private = 'Japan (private)', 
         Norway_public = Norway, Norway_private = 'Norway (private)',
         USA_public = USA, USA_private = 'USA (private)') %>%
  pivot_longer(!year, names_to = c("country",".value"), names_sep = "_") %>%
  pivot_longer(3:4, names_to = "type", values_to = "value") %>%
  ggplot() +
  stat_smooth(aes(x = year, y = value, color = country, linetype = type), 
              span = 0.25, se = FALSE, size=0.75) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Figure 8. The rise of private versus the decline of public 
       wealth in rich countries, 1970-2020", 
       x = "", y = "wealth as as % of national income", color = "", type = "")

4.1.21.1 Step 1

df_f8 %>% 
  select(year, Germany_public = Germany, Germany_private = 'Germany (private)', 
         Spain_public = Spain, Spain_private = 'Spain (private)', 
         France_public = France, France_private = 'France (private)', 
         UK_public  = UK, UK_private = 'UK (private)', 
         Japan_public = Japan, Japan_private = 'Japan (private)', 
         Norway_public = Norway, Norway_private = 'Norway (private)',
         USA_public = USA, USA_private = 'USA (private)') 


4.1.21.2 Step 2.

df_f8 %>% 
  select(year, Germany_public = Germany, Germany_private = 'Germany (private)', 
         Spain_public = Spain, Spain_private = 'Spain (private)', 
         France_public = France, France_private = 'France (private)', 
         UK_public  = UK, UK_private = 'UK (private)', 
         Japan_public = Japan, Japan_private = 'Japan (private)', 
         Norway_public = Norway, Norway_private = 'Norway (private)',
         USA_public = USA, USA_private = 'USA (private)') %>%
  pivot_longer(!year, names_to = c("country",".value"), names_sep = "_") 


4.1.21.3 Step 3.

df_f8 %>% 
  select(year, Germany_public = Germany, Germany_private = 'Germany (private)', 
         Spain_public = Spain, Spain_private = 'Spain (private)', 
         France_public = France, France_private = 'France (private)', 
         UK_public  = UK, UK_private = 'UK (private)', 
         Japan_public = Japan, Japan_private = 'Japan (private)', 
         Norway_public = Norway, Norway_private = 'Norway (private)',
         USA_public = USA, USA_private = 'USA (private)') %>%
  pivot_longer(!year, names_to = c("country",".value"), names_sep = "_") %>%
  pivot_longer(3:4, names_to = "type", values_to = "value")


4.1.21.4 Step 3. Final Step

df_f8 %>% 
  select(year, Germany_public = Germany, Germany_private = 'Germany (private)', 
         Spain_public = Spain, Spain_private = 'Spain (private)', 
         France_public = France, France_private = 'France (private)', 
         UK_public  = UK, UK_private = 'UK (private)', 
         Japan_public = Japan, Japan_private = 'Japan (private)', 
         Norway_public = Norway, Norway_private = 'Norway (private)',
         USA_public = USA, USA_private = 'USA (private)') %>%
  pivot_longer(!year, names_to = c("country",".value"), names_sep = "_") %>%
  pivot_longer(3:4, names_to = "type", values_to = "value") %>%
  ggplot() +
  stat_smooth(aes(x = year, y = value, color = country, linetype = type), 
              formula = y~x, method = "loess", span = 0.25, se = FALSE, size=0.75) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Figure 8. The rise of private versus the decline of public wealth 
       \nin rich countries, 1970-2020", 
       x = "", y = "wealth as as % of national income", color = "", type = "")


4.1.22 F15: Per capita emissions acriss the world, 2019 - add row names + dodge

df_f15 <- read_excel("data/WIR2022s.xlsx", sheet = "data-F15"); df_f15

df_f15 %>% mutate(region = rep(regionWID[!is.na(regionWID)], each = 3)) %>%
  select(region, group, tcap) %>%
  ggplot(aes(x = region, y = tcap, fill = group)) +
  geom_col(position = "dodge") + 
  scale_x_discrete(labels = function(x) stringr::str_wrap(x, width = 10)) +
  labs(title = "Figure 15 Per capita emissions across the world, 2019", 
       x = "", y = "tonnes of CO2e per person per year", fill = "")

4.2 EDA Workflow

4.2.1 EDA Step 0

  1. Choose and clarify a topic to study.
  2. List questions to study
  3. Find data:
  • link to data with a url: universal resource locator in a webpage
  • download data in csv, Excel, etc.

Repeat the process during your EDA.

image

4.2.2 EDA by R Studio: Step 1

In RStudio,

1.1. Project

  • Create a new project: File > New Project; or
  • Open a project: File > Open Project, Open Project in New Session, Open Recent Project
    • It is easier to find an existing project from: File > Recent Project
  • Check there is a file project_name.Rproj in your project folder (directory)

1.2. data folder (directory) data

  • Create a data folder: Press New Folder at the right bottom pane; or
  • Confirm the data folder previously created: Press Files at the right bottom pane
  • If you follow 1, the data folder exists in your project folder

1.3. Move (or copy) data for the project to the data folder

  • If you downloaded the data, it is in your Download folder. Move it to data.
  • Check in your RStudio that your data is in data: Press Files at the right bottom pane and click data, the data folder.

4.2.3 EDA by R Studio: Step 2

2.1. Project Notebook: Memo

  • Create an R Notebook: File > New File > R Notebook

    • You can use R Notebook template in Moodle by moving the template (template.Rmd or template.nb.Rmd) file in your project folder or copy and paste the text file into your new R Notebook.
    • If you use template.nb.Rmd (R Notebook File), choose Open in Editor.
  • Add descriptive title.

2.2. Setup Code Chunk

  • Create a code chunk and add packages to use in the project and RUN the code.

    • library(tidyverse)
    • library(WDI)
    • or any other packages

2.3. Choose Source or Visual editor mode, and start editing Project Notebook

2.4. Edit a new file by saving as for a report

  • File > Save As…

4.2.4 EDA by R Studio: Step 3 - Importing Data

Assign a name you can recall easily when you import data. You may need to reload the data with options.

3.1. Use a package:

  • WDI, wir, eurostat, etc/
  • `wdi_shortname <- WDI(indicator = “indicator’s name”, … )
  • Store the data and use it: write_csv(wdi_shortname, "data/wdi_shortname.csv")
  • wdi_shortname <- read_csv("data/wdi_shortname.csv")

3.2. Use readr to read from data, your data folder

  • df1_shortname <- read_csv("data/file_name.csv")

3.3. Use readr to read using the url of the data

  • df2_shortname <- read_csv("url_of_the_data")
  • Store the data and use it: write_csv(df2_shortname, "data/df2_shortname.csv")
  • df2_shortname <- read_csv("data/df2_shortname.csv")

3.5. Use readxl to read Excel data. Add library(readxl) in the setup and run.

  • df4 <- read_excel("data/file_name.xlsx", sheet = 1)

References: Cheat Sheet - readr, readr, readxl


4.2.5 EDA by R Studio: Step 4 - Data Trasnformation

4.1. Look at the data: suppose df is the data frame

  • It is a good option to change into a tibble: dt <- as_tibble(df)
  • head(df), str(df), summary(df), dt, glimpse(dt)

4.2. Look at each variable

  • categorical? numerical?
  • factor? - forcats

4.3. Variation of each data: suppose x1 is a column name.

  • df %>% ggplot() + geom_histogram(aes(x1), bins = 30)

  • df %>% drop_na(x1): see the rows with a value in x1. If the value is NA, the row is not shown.

    • df_wo_na <- df %>% drop_na(x1) if you want to use only the rows without NA in x1

4.4. Use dpylr and tidyr to change column names, tidy data, and/or summarize data

  • rename, select, filter, arrange, mutate, pivot_longer(), pivot_wider(), group_by and summarize

References: Cheat Sheet - dplyr and tidyr, dplyr, tidyr


4.2.6 EDA by R Studio: Step 5 - Visualize Data

5.1. In combination with Stap 4 - data transformation, try various data visualization.

  • What type of variation occurs within my variables?
  • What type of covariation occurs between my variables?

5.2. Keep a record of what you can observe by the visualization

5.3. Edit the list of questions by adding or polishing

5.4. Select several informative chart and add options

5.5. Look at examples from the textbooks or teaching site to have better visualization

References: Cheat Sheet - ggplot2 ggplot2, ggplot2 book


4.2.7 EDA by R Studio: Step 6 - Conclusions and Questions for Further Study

  1. EDA is an iterative cycle that helps you understand what your data says. When you do EDA, you:

  2. Generate questions about your data

  3. Search for answers by visualising, transforming, and/or modeling your data

Use what you learn to refine your questions and/or generate new questions

EDA is an important part of any data analysis. You can use EDA to make discoveries about the world; or you can use EDA to ensure the quality of your data, asking questions about whether the data meets your standards or not.


4.2.8 Example: WDI


4.2.9 Example: WIR2022

4.3 The Week Five Assignment (in Moodle)

tidyr and WIR2022

  • Create an R Notebook of a Data Analysis containing the following and submit the rendered HTML file (eg. a3_123456.nb.html by replacing 123456 with your ID)
    1. create an R Notebook using the R Notebook Template in Moodle, save as a3_123456.Rmd,
    2. write your name and ID and the contents,
    3. run each code block,
    4. preview to create a3_123456.nb.html,
    5. submit a3_123456.nb.html to Moodle.
  1. Choose a data with at least two categorical variables and at least two numerical variables.

    • Information of the data: Name, Indicator, Description, Source, etc.
    • Explain why you chose the indicator
    • List questions you want to study

  1. Explore the data using visualization using ggplot2

    • Create various charts
    • Create at least one chart with at least two categocial variables and at least one numerical variable.
    • Create at least one chart with at least two numerical variables and at least one categorical variable.
  2. Observations based on your data visualization, and difficulties and questions encountered if any.

Due: 2023-01-23 23:59:00. Submit your R Notebook file in Moodle (The Fourth Assignment). Due on Monday!

LS0tCnRpdGxlOiAnUUFMTDQwMTogRGF0YSBBbmFseXNpcyBmb3IgUmVzZWFyY2hlcnMnCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKICBiZWFtZXJfcHJlc2VudGF0aW9uOiBkZWZhdWx0CiAgaW9zbGlkZXNfcHJlc2VudGF0aW9uOiAKICAgIGRmX3ByaW50OiBwYWdlZAogICAgc21hbGxlcjogeWVzCiAgICBrZWVwX21kOiB5ZXMKICBwZGZfZG9jdW1lbnQ6CiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwotLS0KCiMjIENvdXJzZSBDb250ZW50cyB7LX0KCjEuIDIwMjIuMTIuMDc6IEludHJvZHVjdGlvbjogQWJvdXQgdGhlIGNvdXJzZSBbbGVhZCBieSBUS10KICAgIC0gQW4gaW50cm9kdWN0aW9uIHRvIG9wZW4gYW5kIHB1YmxpYyBkYXRhLCBhbmQgZGF0YSBzY2llbmNlCjIuIDIwMjItMTItMTQ6IEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkgMSBbbGVhZCBieSBoc10gIAogICAgLSBSIEJhc2ljcyB3aXRoIFJTdHVkaW8gYW5kL29yIFJTdHVkaW8uY2xvdWQ7IFRveSBEYXRhCjMuIDIwMjItMTItMjE6IEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkgMiBbbGVhZCBieSBoc10gICAKICAgIC0gUiBNYXJrZG93biwgYHRpZHl2ZXJzZWAgSTogYGRwbHlyYDsgYGdhcG1pbmRlcmAKNC4gMjAyMy0wMS0xMTogRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyAoRURBKSAzIFtsZWFkIGJ5IGhzXSAgCiAgICAtIGB0aWR5dmVyc2VgSUk6IGByZWFkcmAsIGBnZ3Bsb3QyYDsgUHVibGljIERhdGEsIFdESSwgV0lSLCBldGMKNS4gKioyMDIzLTAxLTE4OiBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIChFREEpIDQgW2xlYWQgYnkgaHNdKiogIAogICAgLSBgdGlkeXZlcnNlYCBJSUk6IGB0aWR5cmAsIGV0Yy47IFdESSwgV0lSLCBldGMKNi4gMjAyMy0wMS0yNTogRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpcyAoRURBKSA1IFtsZWFkIGJ5IGhzXSAgCiAgICAtIGB0aWR5dmVyc2VgIElWOyBXREksIFdJUiwgZXRjCjcuIDIwMjMtMDItMDE6IEludHJvZHVjdGlvbiB0byBQUERBQyAgICAgICAgIAogICAgLSBQcm9ibGVtLVBsYW4tRGF0YS1BbmFseXNpcy1Db25jbHVzaW9uIEN5Y2xlOiBbbGVhZCBieSBUS10KOC4gMjAyMy0wMi0wODogTW9kZWwgYnVpbGRpbmcgSSBbbGVhZCBieSBUS10gICAgCiAgICAtIENvbGxlY3RpbmcgYW5kIHZpc3VhbGl6aW5nIGRhdGEgYW5kIEludHJvZHVjdGlvbiB0byBXREkgIAogICAgICAgICAoV29ybGQgRGV2ZWxvcG1lbnQgSW5kaWNhdG9ycyBieSBXb3JsZCBCYW5rKQo5LiAyMDIzLTAyLTE1OiBNb2RlbCBidWlsZGluZyBJSSBbbGVhZCBieSBUS10gICAgCiAgICAtIEFuYWx5emluZyBkYXRhIGFuZCBjb21tdW5pY2F0aW9ucwoxMC4gMjAyMy0wMi0yMjogUHJvamVjdCBQcmVzZW50YXRpb24KCgojIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgKEVEQSkgSQoKIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIElJCgojIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMgSUlJICAKCgoKIyBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzIChFREEpIElWICAKCiMjIFRpZHkgRGF0YQoKIyMjIFJldmlld3MgYW5kIFByZXZpZXdzCgojIyMgRXhhbXBsZTogV29ybGQgSW5lcXVpbGl0eSBSZXBvcnQgLSBXSVIyMDIyCgoqIFdvcmxkIEluZXF1YWxpdHkgUmVwb3J0OiBodHRwczovL3dpcjIwMjIud2lkLndvcmxkLwoqIEV4ZWN1dGl2ZSBTdW1tYXJ5OiBodHRwczovL3dpcjIwMjIud2lkLndvcmxkL2V4ZWN1dGl2ZS1zdW1tYXJ5LwoqIE1ldGhvZG9sb2d5OiBodHRwczovL3dpcjIwMjIud2lkLndvcmxkL21ldGhvZG9sb2d5LwoqIERhdGEgVVJMOiBodHRwczovL3dpcjIwMjIud2lkLndvcmxkL3d3dy1zaXRlL3VwbG9hZHMvMjAyMi8wMy9XSVIyMDIyVGFibGVzRmlndXJlcy1TdW1tYXJ5Lnhsc3gKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZWFkeGwpCmBgYAoKYGBge3Igc3VtbWFyeS1kYXRhLCBjYXNoID0gVFJVRSwgZXZhbCA9IEZBTFNFfQp1cmxfc3VtbWFyeSA8LSAiaHR0cHM6Ly93aXIyMDIyLndpZC53b3JsZC93d3ctc2l0ZS91cGxvYWRzLzIwMjIvMDMvV0lSMjAyMlRhYmxlc0ZpZ3VyZXMtU3VtbWFyeS54bHN4Igpkb3dubG9hZC5maWxlKHVybCA9IHVybF9zdW1tYXJ5LCBkZXN0ZmlsZSA9ICJkYXRhL1dJUjIwMjJzLnhsc3giKSAKYGBgCgpgYGB7cn0KZXhjZWxfc2hlZXRzKCJkYXRhL1dJUjIwMjJzLnhsc3giKQpgYGAKCi0tLQoKIyMjIEYxOiBHbG9iYWwgaW5jb21lIGFuZCB3ZWFsdGggaW5lcXVhbGl0eSwgMjAyMQoKYGBge3IgZGF0YS1mMSwgY2FzaCA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRX0KZGZfZjEgPC0gcmVhZF9leGNlbCgiZGF0YS9XSVIyMDIycy54bHN4Iiwgc2hlZXQgPSAiZGF0YS1GMSIpCmRmX2YxCmBgYAoKCgpgYGB7ciBlY2hvPUZBTFNFfQpkZl9mMV9yZXYgPC0gZGZfZjEgJT4lIHNlbGVjdChjYXQgPSAuLi4xLCAyOjQpICU+JQogIHBpdm90X2xvbmdlcigyOjQsIG5hbWVzX3RvID0gImdyb3VwIiwgdmFsdWVzX3RvID0gInZhbHVlIikKZGZfZjFfcmV2CmBgYAoKLS0tCgpgYGB7cn0KZGZfZjFfcmV2ICU+JQogIGdncGxvdChhZXMoeCA9IGNhdCwgeSA9IHZhbHVlLCBmaWxsID0gZ3JvdXApKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKQpgYGAKCi0tLQoKIyMjIFJlZmVyZW5jZXMgb2YgYHRpZHlyYAoKKiBUZXh0Ym9vazogW1IgZm9yIERhdGEgU2NpZW5jZSxUaWR5IERhdGFdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovdGlkeS1kYXRhLmh0bWwjdGlkeS1kYXRhKQoKIyMjIyBSU3R1ZGlvIFByaW1lcnM6IFNlZSBSZWZlcmVuY2VzIGluIE1vb2RsZSBhdCB0aGUgYm90dG9tCgoqKlRpZHkgWW91ciBEYXRhKioKCiAgLSBSZXNoYXBlIERhdGEKICAtIFNlcGFyYXRlIGFuZCBVbml0ZSBDb2x1bW5zCiAgLSBKb2luIERhdGEgU2V0cwogIAotLS0KCiMjIyBWYXJpYWJsZXMsIHZhbHVlcywgYW5kIG9ic2VydmF0aW9uczogRGVmaW5pdGlvbnMKCiogQSAqKnZhcmlhYmxlKiogaXMgYSBxdWFudGl0eSwgcXVhbGl0eSwgb3IgcHJvcGVydHkgdGhhdCB5b3UgY2FuIG1lYXN1cmUuCiogQSAqKnZhbHVlKiogaXMgdGhlIHN0YXRlIG9mIGEgdmFyaWFibGUgd2hlbiB5b3UgbWVhc3VyZSBpdC4gVGhlIHZhbHVlIG9mIGEgdmFyaWFibGUgbWF5IGNoYW5nZSBmcm9tIG1lYXN1cmVtZW50IHRvIG1lYXN1cmVtZW50LgoqIEFuICoqb2JzZXJ2YXRpb24qKiBvciAqKmNhc2UqKiBpcyBhIHNldCBvZiBtZWFzdXJlbWVudHMgbWFkZSB1bmRlciBzaW1pbGFyIGNvbmRpdGlvbnMgKHlvdSB1c3VhbGx5IG1ha2UgYWxsIG9mIHRoZSBtZWFzdXJlbWVudHMgaW4gYW4gb2JzZXJ2YXRpb24gYXQgdGhlIHNhbWUgdGltZSBhbmQgb24gdGhlIHNhbWUgb2JqZWN0KS4gQW4gb2JzZXJ2YXRpb24gd2lsbCBjb250YWluIHNldmVyYWwgdmFsdWVzLCBlYWNoIGFzc29jaWF0ZWQgd2l0aCBhIGRpZmZlcmVudCB2YXJpYWJsZS4gSeKAmWxsIHNvbWV0aW1lcyByZWZlciB0byBhbiBvYnNlcnZhdGlvbiBhcyBhIGNhc2Ugb3IgZGF0YSBwb2ludC4KKiAqKlRhYnVsYXIgZGF0YSoqIGlzIGEgdGFibGUgb2YgdmFsdWVzLCBlYWNoIGFzc29jaWF0ZWQgd2l0aCBhIHZhcmlhYmxlIGFuZCBhbiBvYnNlcnZhdGlvbi4gVGFidWxhciBkYXRhIGlzIHRpZHkgaWYgZWFjaCB2YWx1ZSBpcyBwbGFjZWQgaW4gaXRzIG93biBjZWxsLCBlYWNoIHZhcmlhYmxlIGluIGl0cyBvd24gY29sdW1uLCBhbmQgZWFjaCBvYnNlcnZhdGlvbiBpbiBpdHMgb3duIHJvdy4KKiBTbyBmYXIsIGFsbCBvZiB0aGUgZGF0YSB0aGF0IHlvdeKAmXZlIHNlZW4gaGFzIGJlZW4gdGlkeS4gSW4gcmVhbC1saWZlLCBtb3N0IGRhdGEgaXNu4oCZdCB0aWR5LCBzbyB3ZeKAmWxsIGNvbWUgYmFjayB0byB0aGVzZSBpZGVhcyBhZ2FpbiBpbiBEYXRhIFdyYW5nbGluZy4KCi0tLQoKIyMjIFRpZHkgRGF0YQoKPiDigJxEYXRhIGNvbWVzIGluIG1hbnkgZm9ybWF0cywgYnV0IFIgcHJlZmVycyBqdXN0IG9uZTogdGlkeSBkYXRhLuKAnSDigJQgR2FycmV0dCBHcm9sZW11bmQKCkRhdGEgY2FuIGNvbWUgaW4gYSB2YXJpZXR5IG9mIGZvcm1hdHMsIGJ1dCBvbmUgZm9ybWF0IGlzIGVhc2llciB0byB1c2UgaW4gUiB0aGFuIHRoZSBvdGhlcnMuIFRoaXMgZm9ybWF0IGlzIGtub3duIGFzIHRpZHkgZGF0YS4gQSBkYXRhIHNldCBpcyB0aWR5IGlmOgoKMS4gRWFjaCB2YXJpYWJsZSBpcyBpbiBpdHMgb3duIGNvbHVtbgoyLiBFYWNoIG9ic2VydmF0aW9uIGlzIGluIGl0cyBvd24gcm93CjMuIEVhY2ggdmFsdWUgaXMgaW4gaXRzIG93biBjZWxsICh0aGlzIGZvbGxvd3MgZnJvbSAjMSBhbmQgIzIpCgo+IOKAnFRpZHkgZGF0YSBzZXRzIGFyZSBhbGwgYWxpa2U7IGJ1dCBldmVyeSBtZXNzeSBkYXRhIHNldCBpcyBtZXNzeSBpbiBpdHMgb3duIHdheS7igJ0g4oCUIEhhZGxleSBXaWNraGFtCgo+IOKAnGFsbCBoYXBweSBmYW1pbGllcyBhcmUgYWxsIGFsaWtlOyBlYWNoIHVuaGFwcHkgZmFtaWx5IGlzIHVuaGFwcHkgaW4gaXRzIG93biB3YXnigJ0gLSBUb2xzdG95J3MgQW5uYSBLYXJlbmluYQoKLS0tCgojIyMgYHRpZHlyYCBCYXNpY3MKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IjEwMCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiZGF0YS90aWR5LTEucG5nIikKYGBgCgoxLiBFYWNoIHZhcmlhYmxlIGlzIGluIGl0cyBvd24gY29sdW1uCjIuIEVhY2ggb2JzZXJ2YXRpb24gaXMgaW4gaXRzIG93biByb3cKCi0tLQoKIyMjIFBpdm90IGRhdGEgZnJvbSB3aWRlIHRvIGxvbmc6IFtgcGl2b3RfbG9uZ2VyKClgXShodHRwczovL3RpZHlyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL3Bpdm90X2xvbmdlci5odG1sKQoKYGBgCnBpdm90X2xvbmdlcihkYXRhLCBjb2xzID0gPGNvbHVtbnMgdG8gcGl2b3QgaW50byBsb25nZXIgZm9ybWF0PiwKICBuYW1lc190byA9IDxuYW1lIG9mIHRoZSBuZXcgY2hhcmFjdGVyIGNvbHVtbj4sICMgZS5nLiAiZ3JvdXAiLCAiY2F0ZWdvcnkiLCAiY2xhc3MiCiAgdmFsdWVzX3RvID0gPG5hbWUgb2YgdGhlIGNvbHVtbiB0aGUgdmFsdWVzIG9mIGNlbGxzIGdvIHRvPikgIyBlLmcuICJ2YWx1ZSIsICJuIgpgYGAKCmBgYHtyfQpkZl9mMQpgYGAKCmBgYHtyfQooZGZfZjFfcmV2IDwtIGRmX2YxICU+JSBwaXZvdF9sb25nZXIoLTEsIG5hbWVzX3RvID0gImdyb3VwIiwgdmFsdWVzX3RvID0gInZhbHVlIikpCmBgYAoKLS0tCgpgYGB7cn0KZGZfZjFfcmV2ICU+JSAKICBnZ3Bsb3QoYWVzKHggPSAuLi4xLCB5ID0gdmFsdWUsIGZpbGwgPSBncm91cCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpCmBgYAoKLS0tCgpgYGB7ciBldmFsPUZBTFNFfQpkZl9mMV9yZXYgJT4lIGZpbHRlcihncm91cCAhPSAiVG9wIDElIikgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fY29sKGFlcyh4ID0gLi4uMSwgeSA9IHZhbHVlLCBmaWxsID0gZ3JvdXApLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBnZW9tX3RleHQoYWVzKHggPSAuLi4xLCB5ID0gdmFsdWUsIGdyb3VwID0gZ3JvdXAsIAogICAgICAgICAgICBsYWJlbCA9IHNjYWxlczo6bGFiZWxfcGVyY2VudChhY2N1cmFjeT0xKSh2YWx1ZSkpLCAKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSkpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDEuIEdsb2JhbCBpbmNvbWUgYW5kIHdlYWx0aCBpbmVxdWFsaXR5LCAyMDIxIiwKICAgICAgIHggPSAiIiwgeSA9ICJTaGFyZSBvZiB0b3RhbCBpbmNvbWUgb3Igd2VhbHRoIiwgZmlsbCA9ICIiKQpgYGAKCi0tLQoKYGBge3IgZWNobz1GQUxTRX0KZGZfZjFfcmV2ICU+JSBmaWx0ZXIoZ3JvdXAgIT0gIlRvcCAxJSIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2NvbChhZXMoeCA9IC4uLjEsIHkgPSB2YWx1ZSwgZmlsbCA9IGdyb3VwKSwgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgZ2VvbV90ZXh0KGFlcyh4ID0gLi4uMSwgeSA9IHZhbHVlLCBncm91cCA9IGdyb3VwLCAKICAgICAgICAgICAgbGFiZWwgPSBzY2FsZXM6OmxhYmVsX3BlcmNlbnQoYWNjdXJhY3k9MSkodmFsdWUpKSwgCiAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpKSArIAogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICBsYWJzKHRpdGxlID0gIkZpZ3VyZSAxLiBHbG9iYWwgaW5jb21lIGFuZCB3ZWFsdGggaW5lcXVhbGl0eSwgMjAyMSIsCiAgICAgICB4ID0gIiIsIHkgPSAiU2hhcmUgb2YgdG90YWwgaW5jb21lIG9yIHdlYWx0aCIsIGZpbGwgPSAiIikKYGBgCioqSW50ZXJwcmV0YXRpb24qKjogVGhlIGdsb2JhbCBib3R0b20gNTAlIGNhcHR1cmVzIDguNSUgb2YgdG90YWwgaW5jb21lIG1lYXN1cmVkIGF0IFB1cmNoYXNpbmcgUG93ZXIgUGFyaXR5IChQUFApLiBUaGUgZ2xvYmFsIGJvdHRvbSA1MCUgb3ducyAyJSBvZiB3ZWFsdGggKGF0IFB1cmNoYXNpbmcgUG93ZXIgUGFyaXR5KS4gVGhlIGdsb2JhbCB0b3AgMTAlIG93bnMgNzYlIG9mIHRvdGFsIEhvdXNlaG9sZCB3ZWFsdGggYW5kIGNhcHR1cmVzIDUyJSBvZiB0b3RhbCBpbmNvbWUgaW4gMjAyMS4gTm90ZSB0aGF0IHRvcCB3ZWFsdGggaG9sZGVycyBhcmUgbm90IG5lY2Vzc2FyaWx5IHRvcCBpbmNvbWUgaG9sZGVycy4gSW5jb21lcyBhcmUgbWVhc3VyZWQgYWZ0ZXIgdGhlIG9wZXJhdGlvbiBvZiBwZW5zaW9uIGFuZCB1bmVtcGxveW1lbnQgc3lzdGVtcyBhbmQgYmVmb3JlIHRheGVzIGFuZCB0cmFuc2ZlcnMuICAKKipTb3VyY2VzIGFuZCBzZXJpZXMqKjogd2lyMjAyMi53aWQud29ybGQvbWV0aG9kb2xvZ3kuCgotLS0KCiMjIyBGMjogVGhlIHBvb3Jlc3QgaGFsZiBsYWdzIGJlaGluZDogQm90dG9tIDUwJSwgbWlkZGxlIDQwJSBhbmQgdG9wIDEwJSBpbmNvbWUgc2hhcmVzIGFjcm9zcyB0aGUgd29ybGQgaW4gMjAyMQoKYGBge3J9CmRmX2YyIDwtIHJlYWRfZXhjZWwoImRhdGEvV0lSMjAyMnMueGxzeCIsIHNoZWV0ID0gImRhdGEtRjIiKQpkZl9mMgpgYGAKCi0tLQoKYGBge3J9CmRmX2YyICU+JSBwaXZvdF9sb25nZXIoY29scyA9IDM6NSwgbmFtZXNfdG8gPSAiZ3JvdXAiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKQpgYGAKCi0tLQoKYGBge3J9CmRmX2YyICU+JSBwaXZvdF9sb25nZXIoY29scyA9IDM6NSwgbmFtZXNfdG8gPSAiZ3JvdXAiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBpc28sIHkgPSB2YWx1ZSwgZmlsbCA9IGdyb3VwKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikKYGBgCgotLS0KCiMjIyBQaXZvdCBkYXRhIGZyb20gbG9uZyB0byB3aWRlOiAKW2BwaXZvdF93aWRlcigpYF0oaHR0cHM6Ly90aWR5ci50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9waXZvdF93aWRlci5odG1sKQpJbiBDb25zb2xlOiB2aWduZXR0ZSgicGl2b3QiKSAKCmBgYApwaXZvdF93aWRlcihkYXRhLCAKICBuYW1lc19mcm9tID0gPG5hbWUgb2YgdGhlIGNvbHVtbiAob3IgY29sdW1ucykgdG8gZ2V0IHRoZSBuYW1lIG9mIHRoZSBvdXRwdXQgY29sdW1uPiwKICB2YWx1ZXNfZnJvbSA9IDxuYW1lIG9mIHRoZSBjb2x1bW4gdG8gZ2V0IHRoZSB2YWx1ZSBvZiB0aGUgb3V0cHV0PikgCmBgYAoKCi0tLQoKYGBge3IgZWNobyA9IEZBTFNFfQpkZl9mMiAlPiUgcGl2b3RfbG9uZ2VyKGNvbHMgPSAzOjUsIG5hbWVzX3RvID0gImdyb3VwIiwgdmFsdWVzX3RvID0gInZhbHVlIikKYGBgCgpgYGAKcGl2b3Rfd2lkZXIoZGF0YSwgbmFtZXNfZnJvbSA9IGdyb3VwLCB2YWx1ZXNfZnJvbSA9IHZhbHVlKSAKYGBgCgotLS0KCiMjIyBQcmFjdGljZTogRjQgYW5kIEYxMwoKRjQgYW5kIEYxMyBhcmUgc2ltaWxhci4gUGxlYXNlIHVzZSBgcGl2b3RfbG9uZ2VyYCB0byB0aWR5IHRoZSBkYXRhIGFuZCBjcmVhdGUgY2hhcnRzLgoKKiAqKlJlZmVyZW5jZXMqKjogaHR0cHM6Ly9kcy1zbC5naXRodWIuaW8vZGF0YS1hbmFseXNpcy93aXIyMDIyLm5iLmh0bWwKCiMjIyMgRG9uZSBMYXN0IFdlZWsKCiogRjEyOiBGZW1hbGUgc2hhcmUgaW4gZ2xvYmFsIGxhYm9yIGluY29tZXMsIDE5OTAtMjAyMAoqIEYxNDogR2xvYmFsIGNhcmJvbiBpbmVxdWFsaXR5LCAyMDE5LiBHcm91cCBjb250cmlidXRpb24gdG8gd29ybGQgZW1pc3Npb25zICglKQoKLS0tCgojIyMgRjM6IFRvcCAxMC9Cb3R0b20gNTAgaW5jb21lIGdhcHMgYWNyb3NzIHRoZSB3b3JsZCwgMjAyMQoKCmBgYHtyfQpkZl9mMyA8LSByZWFkX2V4Y2VsKCJkYXRhL1dJUjIwMjJzLnhsc3giLCBzaGVldCA9ICJkYXRhLUYzIikKZGZfZjMKYGBgCgotLS0KCiMjIyBGMzogVG9wIDEwL0JvdHRvbSA1MCBpbmNvbWUgZ2FwcyBhY3Jvc3MgdGhlIHdvcmxkLCAyMDIxIC0gT3JpZ2luYWwKCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9IjEwMCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiZGF0YS9GMy5wbmciKQpgYGAKCi0tLQoKKiBUbyAxMCAvIEJvdHRvbSA1MCByYXRpbyBoYXMgNSBjbGFzc2VzOiA1LTEyLCAxMi0xMywgMTMtMTYsIDE2LTE5LCAxOS0xNDAKCmBgYHtyfQpkZl9mMyRUMTBCNTAgJT4lIHN1bW1hcnkoKQpgYGAKCi0tLQoKYGBge3J9CmRmX2YzICU+JSBnZ3Bsb3QoKSArIGdlb21faGlzdG9ncmFtKGFlcyhUMTBCNTApKQpgYGAKCi0tLQoKYGBge3J9CmRmX2YzICU+JSBhcnJhbmdlKGRlc2MoVDEwQjUwKSkKYGBgCgotLS0KCmBgYHtyfQpkZl9mMyAlPiUgCiAgbXV0YXRlKGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCA9IGN1dChUMTBCNTAsYnJlYWtzID0gYyg1LCAxMiwgMTMsIDE2LCAxOSwxNDApLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gRkFMU0UpKSAKYGBgCgotLS0KCmBgYHtyfQp3b3JsZF9tYXAgPC0gbWFwX2RhdGEoIndvcmxkIikKZGZfZjMgJT4lIG11dGF0ZShgVG9wIDEwIEJvdHRvbSA1MCBSYXRpb2AgPSBjdXQoVDEwQjUwLGJyZWFrcyA9IGMoNSwgMTIsIDEzLCAxNiwgMTksMTQwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlLmxvd2VzdCA9IEZBTFNFKSkgJT4lCiAgZ2dwbG90KGFlcyhtYXBfaWQgPSBDb3VudHJ5KSkgKyAKICBnZW9tX21hcChhZXMoZmlsbCA9IGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCksIG1hcCA9IHdvcmxkX21hcCkgKyAKICBleHBhbmRfbGltaXRzKHggPSB3b3JsZF9tYXAkbG9uZywgeSA9IHdvcmxkX21hcCRsYXQpCmBgYAoKLS0tCgpgYGB7cn0Kd29ybGRfbWFwX3dpciA8LSB3b3JsZF9tYXAKd29ybGRfbWFwX3dpciRyZWdpb25bCiAgd29ybGRfbWFwX3dpciRyZWdpb249PSJEZW1vY3JhdGljIFJlcHVibGljIG9mIHRoZSBDb25nbyJdPC0iRFIgQ29uZ28iCndvcmxkX21hcF93aXIkcmVnaW9uW3dvcmxkX21hcF93aXIkcmVnaW9uPT0iUmVwdWJsaWMgb2YgQ29uZ28iXTwtIkNvbmdvIgp3b3JsZF9tYXBfd2lyJHJlZ2lvblt3b3JsZF9tYXBfd2lyJHJlZ2lvbj09Ikl2b3J5IENvYXN0Il08LSJDb3RlIGRJdm9pcmUiCndvcmxkX21hcF93aXIkcmVnaW9uW3dvcmxkX21hcF93aXIkcmVnaW9uPT0iVmlldG5hbSJdPC0iVmlldCBOYW0iCndvcmxkX21hcF93aXIkcmVnaW9uW3dvcmxkX21hcF93aXIkcmVnaW9uPT0iUnVzc2lhIl08LSJSdXNzaWFuIEZlZGVyYXRpb24iCndvcmxkX21hcF93aXIkcmVnaW9uW3dvcmxkX21hcF93aXIkcmVnaW9uPT0iU291dGggS29yZWEiXTwtIktvcmVhIgp3b3JsZF9tYXBfd2lyJHJlZ2lvblt3b3JsZF9tYXBfd2lyJHJlZ2lvbj09IlVLIl08LSJVbml0ZWQgS2luZ2RvbSIKd29ybGRfbWFwX3dpciRyZWdpb25bd29ybGRfbWFwX3dpciRyZWdpb249PSJCcnVuZWkiXTwtIkJydW5laSBEYXJ1c3NhbGFtIgp3b3JsZF9tYXBfd2lyJHJlZ2lvblt3b3JsZF9tYXBfd2lyJHJlZ2lvbj09Ikxhb3MiXTwtIkxhbyBQRFIiCndvcmxkX21hcF93aXIkcmVnaW9uW3dvcmxkX21hcF93aXIkcmVnaW9uPT0iQ290ZSBkSXZvaXJlIl08LSJDb3RlIGQnSXZvaXJlIgp3b3JsZF9tYXBfd2lyJHJlZ2lvblt3b3JsZF9tYXBfd2lyJHJlZ2lvbj09IkNhcGUgVmVyZGUiXTwtICJDYWJvIFZlcmRlIgp3b3JsZF9tYXBfd2lyJHJlZ2lvblt3b3JsZF9tYXBfd2lyJHJlZ2lvbj09IlN5cmlhIl08LSAiU3lyaWFuIEFyYWIgUmVwdWJsaWMiCndvcmxkX21hcF93aXIkcmVnaW9uW3dvcmxkX21hcF93aXIkcmVnaW9uPT0iVHJpbmlkYWQiXTwtICJUcmluaWRhZCBhbmQgVG9iYWdvIgp3b3JsZF9tYXBfd2lyJHJlZ2lvblt3b3JsZF9tYXBfd2lyJHJlZ2lvbj09IlRvYmFnbyJdPC0gIlRyaW5pZGFkIGFuZCBUb2JhZ28iCmBgYAogIAotLS0KCmBgYHtyfQpkZl9mMyAlPiUgbXV0YXRlKGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCA9IAogICAgY3V0KFQxMEI1MCwgYnJlYWtzID0gYyg1LCAxMiwgMTMsIDE2LCAxOSwxNDApLCBpbmNsdWRlLmxvd2VzdCA9IEZBTFNFKSkgJT4lCiAgZ2dwbG90KGFlcyhtYXBfaWQgPSBDb3VudHJ5KSkgKyAKICBnZW9tX21hcChhZXMoZmlsbCA9IGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCksIAogICAgbWFwID0gd29ybGRfbWFwX3dpcikgKyAKICAgIGV4cGFuZF9saW1pdHMoeCA9IHdvcmxkX21hcF93aXIkbG9uZywgeSA9IHdvcmxkX21hcF93aXIkbGF0KQpgYGAKCgoKLS0tCgpgYGB7cn0KZGZfZjMgJT4lIG11dGF0ZShgVG9wIDEwIEJvdHRvbSA1MCBSYXRpb2AgPSAKICAgIGN1dChUMTBCNTAsYnJlYWtzID0gYyg1LCAxMiwgMTMsIDE2LCAxOSwxNDApLCBpbmNsdWRlLmxvd2VzdCA9IEZBTFNFKSkgJT4lCiAgZ2dwbG90KGFlcyhtYXBfaWQgPSBDb3VudHJ5KSkgKyBnZW9tX21hcChhZXMoZmlsbCA9IGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCksIAogICAgbWFwID0gd29ybGRfbWFwX3dpcikgKyBleHBhbmRfbGltaXRzKHggPSB3b3JsZF9tYXBfd2lyJGxvbmcsIHkgPSB3b3JsZF9tYXBfd2lyJGxhdCkgKyAKICBjb29yZF9tYXAoIm9ydGhvZ3JhcGhpYyIsIG9yaWVudGF0aW9uID0gYygyNSwgNjAsIDApKQpgYGAKCi0tLQoKYGBge3J9CmRmX2YzICU+JSBtdXRhdGUoYFRvcCAxMCBCb3R0b20gNTAgUmF0aW9gID0gCiAgY3V0KFQxMEI1MCxicmVha3MgPSBjKDUsIDEyLCAxMywgMTYsIDE5LDE0MCksIGluY2x1ZGUubG93ZXN0ID0gRkFMU0UpKSAlPiUKICBnZ3Bsb3QoYWVzKG1hcF9pZCA9IENvdW50cnkpKSArIGdlb21fbWFwKGFlcyhmaWxsID0gYFRvcCAxMCBCb3R0b20gNTAgUmF0aW9gKSwgCiAgICBtYXAgPSB3b3JsZF9tYXBfd2lyKSArIGV4cGFuZF9saW1pdHMoeCA9IHdvcmxkX21hcF93aXIkbG9uZywgeSA9IHdvcmxkX21hcF93aXIkbGF0KSArIAogIGNvb3JkX21hcCgib3J0aG9ncmFwaGljIiwgb3JpZW50YXRpb24gPSBjKDE1LCAtODAsIDApKQpgYGAKCi0tLQoKCmBgYHtyfQpkZl9mMyAlPiUgbXV0YXRlKGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCA9IAogIGN1dChUMTBCNTAsYnJlYWtzID0gYyg1LCAxMiwgMTMsIDE2LCAxOSwxNDApLCBpbmNsdWRlLmxvd2VzdCA9IEZBTFNFKSkgJT4lCiAgZ2dwbG90KGFlcyhtYXBfaWQgPSBDb3VudHJ5KSkgKyBnZW9tX21hcChhZXMoZmlsbCA9IGBUb3AgMTAgQm90dG9tIDUwIFJhdGlvYCksIAogICAgbWFwID0gd29ybGRfbWFwX3dpcikgKyAKICBleHBhbmRfbGltaXRzKHggPSB3b3JsZF9tYXBfd2lyJGxvbmcsIHkgPSB3b3JsZF9tYXBfd2lyJGxhdCkKYGBgCgotLS0KCmBgYHtyIGV2YWwgPSBGQUxTRX0KZGZfZjMgJT4lIAogIG11dGF0ZShgVG9wIDEwIEJvdHRvbSA1MCBSYXRpb2AgPSAKICAgICAgICBjdXQoVDEwQjUwLGJyZWFrcyA9IGMoNSwgMTIsIDEzLCAxNiwgMTksMTQwKSwgaW5jbHVkZS5sb3dlc3QgPSBGQUxTRSkpICU+JQogIGdncGxvdChhZXMobWFwX2lkID0gQ291bnRyeSkpICsgCiAgZ2VvbV9tYXAoYWVzKGZpbGwgPSBgVG9wIDEwIEJvdHRvbSA1MCBSYXRpb2ApLCBtYXAgPSB3b3JsZF9tYXBfd2lyKSArIAogIGV4cGFuZF9saW1pdHMoeCA9IHdvcmxkX21hcF93aXIkbG9uZywgeSA9IHdvcmxkX21hcF93aXIkbGF0KSAgKyAKICBsYWJzKHRpdGxlID0gIkZpZ3VyZSAzLiBUb3AgMTAvQm90dG9tIDUwIGluY29tZSBnYXBzIGFjcm9zcyB0aGUgd29ybGQsIDIwMjEiLAogICAgICAgeCA9ICIiLCB5ID0gIiIsIGZpbGwgPSAiVG9wIDEwL0JvdHRvbSA1MCByYXRpbyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCkpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0nWWxPclJkJykKYGBgCgotLS0KCmBgYHtyIGVjaG8gPSBGQUxTRX0KZGZfZjMgJT4lIAogIG11dGF0ZShgVG9wIDEwIEJvdHRvbSA1MCBSYXRpb2AgPSBjdXQoVDEwQjUwLGJyZWFrcyA9IGMoNSwgMTIsIDEzLCAxNiwgMTksMTQwKSwgaW5jbHVkZS5sb3dlc3QgPSBGQUxTRSkpICU+JQogIGdncGxvdChhZXMobWFwX2lkID0gQ291bnRyeSkpICsgZ2VvbV9tYXAoYWVzKGZpbGwgPSBgVG9wIDEwIEJvdHRvbSA1MCBSYXRpb2ApLCBtYXAgPSB3b3JsZF9tYXBfd2lyKSArIGV4cGFuZF9saW1pdHMoeCA9IHdvcmxkX21hcF93aXIkbG9uZywgeSA9IHdvcmxkX21hcF93aXIkbGF0KSAgKyAKICBsYWJzKHRpdGxlID0gIkZpZ3VyZSAzLiBUb3AgMTAvQm90dG9tIDUwIGluY29tZSBnYXBzIGFjcm9zcyB0aGUgd29ybGQsIDIwMjEiLAogICAgICAgeCA9ICIiLCB5ID0gIiIsIGZpbGwgPSAiVG9wIDEwL0JvdHRvbSA1MCByYXRpbyIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIsIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCkpICsgCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZT0nWWxPclJkJykKYGBgCgotLS0KCmBgYHtyfQpkZl9mMyAlPiUgYW50aV9qb2luKHdvcmxkX21hcF93aXIsIGJ5ID0gYygiQ291bnRyeSIgPSAicmVnaW9uIikpCmBgYAoKKipGaWx0ZXJpbmcgam9pbnMqKgoKKiBgYW50aV9qb2luKHgseSwgLi4uKWA6IHJldHVybiBhbGwgcm93cyBmcm9tIHggd2l0aG91dCBhIG1hdGNoIGluIHkuCiogYHNlbWlfam9pbih4LHksIC4uLilgOiByZXR1cm4gYWxsIHJvd3MgZnJvbSB4IHdpdGggYSBtYXRjaCBpbiB5LgoKQ2hlY2sgYGRwbHlyYCBjaGVhdCBzaGVldCwgYW5kIFBvc2l0IFByaW1lcnMgVGlkeSBEYXRhLgoKLS0tCgojIyMgUmVtYWluaW5nIENoYXJ0cwoKKiBGNTogR2xvYmFsIGluY29tZSBpbmVxdWFsaXR5OiBUMTAvQjUwIHJhdGlvLCAxODIwLTIwMjAgLSBmaXQgY3VydmUKKiBGOTogQXZlcmFnZSBhbm51YWwgd2VhbHRoIGdyb3d0aCByYXRlLCAxOTk1LTIwMjEgLSBmaXQgY3VydmUgKyBhbHBoYQoqIEY3OiBHbG9iYWwgaW5jb21lIGluZXF1YWxpdHksIDE4MjAtMjAyMCAtIHBpdm90ICsgZml0IGN1cnZlCiogRjEwOiBUaGUgc2hhcmUgb2Ygd2VhbHRoIG93bmVkIGJ5IHRoZSBnbG9iYWwgMC4xJSBhbmQgYmlsbGlvbmFpcmVzLCAyMDIxIC0gcGl2b3QgKyBmaXQgY3VydmUKCgoqIEY2OiBHbG9iYWwgaW5jb21lIGluZXF1YWxpdHk6IEJldHdlZW4gdnMuIFdpdGhpbiBjb3VudHJ5IGluZXF1YWxpdHkgKFRoZWlsIGluZGV4KSwgMTgyMC0yMDIwIC0gcGl2b3QgKyBhcmVhCgoqIEYxMTogVG9wIDElIHZzIGJvdHRvbSA1MCUgd2VhbHRoIHNoYXJlcyBpbiBXZXN0ZXJuIEV1cm9wZSBhbmQgdGhlIFVTLCAxOTEwLTIwMjAgLSBwaXZvdCBuYW1lX3NlcCArIGZpdCBjdXJ2ZQoqIEY4OiBUaGUgcmlzZSBvZiBwcml2YXRlIHZlcnN1cyB0aGUgZGVjbGluZSBvZiBwdWJsaWMgd2VhbHRoIGluIHJpY2ggY291bnRyaWVzLCAxOTcwLTIwMjAgLSByZW5hbWUgKyBwaXZvdCArIHBpdm90ICsgZml0IGN1cnZlCgoqIEYxNTogUGVyIGNhcGl0YSBlbWlzc2lvbnMgYWNyaXNzIHRoZSB3b3JsZCwgMjAxOSAtIGFkZCByb3cgbmFtZXMgKyBkb2RnZQoKCi0tLQoKIyMjIEY1OiBHbG9iYWwgaW5jb21lIGluZXF1YWxpdHk6IFQxMC9CNTAgcmF0aW8sIDE4MjAtMjAyMAoKYGBge3IgZGF0YS1mNSwgY2FzaCA9IFRSVUV9CihkZl9mNSA8LSByZWFkX2V4Y2VsKCJkYXRhL1dJUjIwMjJzLnhsc3giLCBzaGVldCA9ICJkYXRhLUY1IikpCmBgYAoKLS0tCgpgYGB7cn0KZGZfZjUgJT4lIGdncGxvdChhZXMoeCA9IHksIHkgPSB0MTBiNTApKSArIGdlb21fbGluZSgpICsgZ2VvbV9zbW9vdGgoc3Bhbj0wLjI1LCBzZT1GQUxTRSkKYGBgCgotLS0KCiMjIyBGOTogQXZlcmFnZSBhbm51YWwgd2VhbHRoIGdyb3d0aCByYXRlLCAxOTk1LTIwMjEgLSBmaXQgY3VydmUgKyBhbHBoYQoKYGBge3IgZGF0YS1mOSwgY2FzaCA9IFRSVUV9CmRmX2Y5IDwtIHJlYWRfZXhjZWwoImRhdGEvV0lSMjAyMnMueGxzeCIsIHNoZWV0ID0gImRhdGEtRjkiKTsgZGZfZjkKYGBgCgotLS0KCmBgYHtyfQpkZl9mOSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcCwgeSA9IGBXZWFsdGggZ3Jvd3RoIDE5OTUtMjAyMWApKSArIGdlb21fc21vb3RoKHNwYW4gPSAwLjMwLCBzZSA9IEZBTFNFKQpgYGAKCi0tLQoKIyMjIEY3OiBHbG9iYWwgaW5jb21lIGluZXF1YWxpdHksIDE4MjAtMjAyMCAtIHBpdm90ICsgZml0IGN1cnZlCgpgYGB7ciBkYXRhLWY3LCBjYXNoID0gVFJVRX0KZGZfZjcgPC0gcmVhZF9leGNlbCgiZGF0YS9XSVIyMDIycy54bHN4Iiwgc2hlZXQgPSAiZGF0YS1GNyIpOyBkZl9mNwpgYGAKCi0tLQoKYGBge3J9CmRmX2Y3ICU+JSAKICBwaXZvdF9sb25nZXIoY29scyA9IDI6NCwgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQogIGdncGxvdChhZXMoeCA9IHksIHkgPSB2YWx1ZSwgY29sb3IgPSB0eXBlKSkgKwogIHN0YXRfc21vb3RoKGZvcm11bGEgPSB5fngsIG1ldGhvZCA9ICJsb2VzcyIsIHNwYW4gPSAwLjI1LCBzZSA9IEZBTFNFKQpgYGAKCi0tLQoKIyMjIEYxMDogVGhlIHNoYXJlIG9mIHdlYWx0aCBvd25lZCBieSB0aGUgZ2xvYmFsIDAuMSUgYW5kIGJpbGxpb25haXJlcywgMjAyMSAtIHBpdm90ICsgZml0IGN1cnZlCgpgYGB7ciBkYXRhLWYxMCwgY2FzaCA9IFRSVUV9CmRmX2YxMCA8LSByZWFkX2V4Y2VsKCJkYXRhL1dJUjIwMjJzLnhsc3giLCBzaGVldCA9ICJkYXRhLUYxMCIpOyBkZl9mMTAKYGBgCgotLS0KCmBgYHtyfQpkZl9mMTAgJT4lIAogIHNlbGVjdCh5ZWFyLCAiR2xvYmFsIEJpbGxpb25haXJlIFdlYWx0aCIgPSBibl9oaHdlYWwsICJUb3AgMC4wMSUiID0gdG9wMC4xX2hod2VhbCkgJT4lCiAgcGl2b3RfbG9uZ2VyKCF5ZWFyLCBuYW1lc190byA9ICJncm91cCIsIi52YWx1ZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpCmBgYAoKLS0tCgpgYGB7cn0KZGZfZjEwICU+JSAKICBzZWxlY3QoeWVhciwgIkdsb2JhbCBCaWxsaW9uYWlyZSBXZWFsdGgiID0gYm5faGh3ZWFsLCAiVG9wIDAuMDElIiA9IHRvcDAuMV9oaHdlYWwpICU+JQogIHBpdm90X2xvbmdlcigheWVhciwgbmFtZXNfdG8gPSAiZ3JvdXAiLCIudmFsdWUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBnZ3Bsb3QoKSArCiAgc3RhdF9zbW9vdGgoYWVzKHggPSB5ZWFyLCB5ID0gdmFsdWUsIGNvbG9yID0gZ3JvdXApLCBmb3JtdWxhID0geX54LCBtZXRob2QgPSAibG9lc3MiLCBzcGFuID0gMC4yNSwgc2UgPSBGQUxTRSkKYGBgCgotLS0KCiMjIyBGNjogR2xvYmFsIGluY29tZSBpbmVxdWFsaXR5OiBCZXR3ZWVuIHZzLiBXaXRoaW4gY291bnRyeSBpbmVxdWFsaXR5IChUaGVpbCBpbmRleCksIDE4MjAtMjAyMCAtIHBpdm90ICsgYXJlYQoKYGBge3IgZGF0YS1mNiwgY2FzaCA9IFRSVUV9CmRmX2Y2IDwtIHJlYWRfZXhjZWwoImRhdGEvV0lSMjAyMnMueGxzeCIsIHNoZWV0ID0gImRhdGEtRjYiKTsgZGZfZjYKYGBgCgotLS0KCmBgYHtyIGV2YWwgPUZBTFNFfQpkZl9mNiAlPiUgc2VsZWN0KHllYXIgPSAiLi4uMSIsIDI6MykgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAyOjMsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBtdXRhdGUodHlwZXMgPSBmYWN0b3IodHlwZSwgCiAgICAgIGxldmVscyA9IGMoIldpdGhpbi1jb3VudHJ5IGluZXF1YWxpdHkiLCAiQmV0d2Vlbi1jb3VudHJ5IGluZXF1YWxpdHkiKSkpICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB2YWx1ZSwgZmlsbCA9IHR5cGVzKSkgKwogIGdlb21fYXJlYSgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHJvdW5kKHNlcSgxODIwLCAyMDIwLCBieSA9IDIwKSwxKSkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cmV2KHNjYWxlczo6aHVlX3BhbCgpKDIpKSwgCiAgICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHN0cl93cmFwKHgsIHdpZHRoID0gMTUpKSArCiAgbGFicyh0aXRsZSA9ICJGaWd1cmUgNi4gR2xvYmFsIGluY29tZSBpbmVxdWFsaXR5OiAKICAgICAgIFxuQmV0d2VlbiB2cy4gd2l0aGluIGNvdW50cnkgaW5lcXVhbGl0eSAoVGhlaWwgaW5kZXgpLCAxODIwLTIwMjAiLAogICAgICAgeCA9ICIiLCB5ID0gIlNoYXJlIG9mIGdsb2JhbCBpbmVxdWFsaXR5ICglIG9mIHRvdGFsIFRoZWlsIGluZGV4KSIsIGZpbGwgPSAiIikgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxODUwLCB5ID0gMC4yOCwgCiAgICAgIGxhYmVsID0gc3RyaW5ncjo6c3RyX3dyYXAoIjE4MjA6IEJldHdlZW4gY291bnRyeSBpbmVxdWFsaXR5IHJlcHJlc2VudHMgMTElIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9mIGdsb2JhbCBpbmVxdWFsaXR5Iiwgd2lkdGggPSAyMCksIHNpemUgPSAzKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDE5ODAsIHkgPSAwLjcwLCAKICAgICAgbGFiZWwgPSBzdHJpbmdyOjpzdHJfd3JhcCgiMTk4MDogQmV0d2VlbiBjb3VudHJ5IGluZXF1YWxpdHkgcmVwcmVzZW50cyA1NyUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2YgZ2xvYmFsIGluZXF1YWxpdHkiLCB3aWR0aCA9IDIwKSwgc2l6ZSA9IDMpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxOTkwLCB5ID0gMC4zMCwgCiAgICAgIGxhYmVsID0gc3RyaW5ncjo6c3RyX3dyYXAoIjIwMjA6IEJldHdlZW4gY291bnRyeSBpbmVxdWFsaXR5IHJlcHJlc2VudHMgMzIlIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9mIGdsb2JhbCBpbmVxdWFsaXR5Iiwgd2lkdGggPSAyMCksIHNpemUgPSAzKQpgYGAKCi0tLQoKCmBgYHtyIGVjaG8gPUZBTFNFfQpkZl9mNiAlPiUgc2VsZWN0KHllYXIgPSAiLi4uMSIsIDI6MykgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAyOjMsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBtdXRhdGUodHlwZXMgPSBmYWN0b3IodHlwZSwgCiAgICAgIGxldmVscyA9IGMoIldpdGhpbi1jb3VudHJ5IGluZXF1YWxpdHkiLCAiQmV0d2Vlbi1jb3VudHJ5IGluZXF1YWxpdHkiKSkpICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB2YWx1ZSwgZmlsbCA9IHR5cGVzKSkgKwogIGdlb21fYXJlYSgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHJvdW5kKHNlcSgxODIwLCAyMDIwLCBieSA9IDIwKSwxKSkgKyAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cmV2KHNjYWxlczo6aHVlX3BhbCgpKDIpKSwgCiAgICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHN0cl93cmFwKHgsIHdpZHRoID0gMTUpKSArCiAgbGFicyh0aXRsZSA9ICJGaWd1cmUgNi4gR2xvYmFsIGluY29tZSBpbmVxdWFsaXR5OiAKICAgICAgIFxuQmV0d2VlbiB2cy4gd2l0aGluIGNvdW50cnkgaW5lcXVhbGl0eSAoVGhlaWwgaW5kZXgpLCAxODIwLTIwMjAiLAogICAgICAgeCA9ICIiLCB5ID0gIlNoYXJlIG9mIGdsb2JhbCBpbmVxdWFsaXR5ICglIG9mIHRvdGFsIFRoZWlsIGluZGV4KSIsIGZpbGwgPSAiIikgKyAKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxODUwLCB5ID0gMC4yOCwgCiAgICAgIGxhYmVsID0gc3RyaW5ncjo6c3RyX3dyYXAoIjE4MjA6IEJldHdlZW4gY291bnRyeSBpbmVxdWFsaXR5IHJlcHJlc2VudHMgMTElIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9mIGdsb2JhbCBpbmVxdWFsaXR5Iiwgd2lkdGggPSAyMCksIHNpemUgPSAzKSArIAogIGFubm90YXRlKCJ0ZXh0IiwgeCA9IDE5ODAsIHkgPSAwLjcwLCAKICAgICAgbGFiZWwgPSBzdHJpbmdyOjpzdHJfd3JhcCgiMTk4MDogQmV0d2VlbiBjb3VudHJ5IGluZXF1YWxpdHkgcmVwcmVzZW50cyA1NyUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2YgZ2xvYmFsIGluZXF1YWxpdHkiLCB3aWR0aCA9IDIwKSwgc2l6ZSA9IDMpICsKICBhbm5vdGF0ZSgidGV4dCIsIHggPSAxOTkwLCB5ID0gMC4zMCwgCiAgICAgIGxhYmVsID0gc3RyaW5ncjo6c3RyX3dyYXAoIjIwMjA6IEJldHdlZW4gY291bnRyeSBpbmVxdWFsaXR5IHJlcHJlc2VudHMgMzIlIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9mIGdsb2JhbCBpbmVxdWFsaXR5Iiwgd2lkdGggPSAyMCksIHNpemUgPSAzKQpgYGAKCgotLS0KCiMjIyBGMTE6IFRvcCAxJSB2cyBib3R0b20gNTAlIHdlYWx0aCBzaGFyZXMgaW4gV2VzdGVybiBFdXJvcGUgYW5kIHRoZSBVUywgMTkxMC0yMDIwIC0gcGl2b3QgbmFtZV9zZXAgKyBmaXQgY3VydmUKCmBgYHtyIGRhdGEtZjExLCBjYXNoID0gVFJVRX0KZGZfZjExIDwtIHJlYWRfZXhjZWwoImRhdGEvV0lSMjAyMnMueGxzeCIsIHNoZWV0ID0gImRhdGEtRjExIik7IGRmX2YxMQpgYGAKCi0tLQoKYGBge3IgZXZhbCA9IEZBTFNFfQpkZl9mMTEgJT4lIAogIHJlbmFtZSgheWVhciwgVVNfYm90NTAgPSBVU2JvdDUwLCBVU190b3AxID0gVVN0b3AxLCAKICAgICAgICAgRVVfYm90NTAgPSBFVWJvdDUwLCBFVV90b3AxID0gRVV0b3AxKSAlPiUKICBwaXZvdF9sb25nZXIoIXllYXIsIG5hbWVzX3RvID0gYygiZ3JvdXAiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKSAlPiUKICBwaXZvdF9sb25nZXIoMzo0LCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lCiAgZ2dwbG90KCkgKwogIHN0YXRfc21vb3RoKGFlcyh4ID0geWVhciwgeSA9IHZhbHVlLCBjb2xvciA9IGdyb3VwLCBsaW5ldHlwZSA9IHR5cGUpLCAKICAgICAgICAgICAgICBzcGFuID0gMC4yNSwgc2UgPSBGQUxTRSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSByb3VuZChzZXEoMTkxMCwgMjAyMCwgYnkgPSAxMCksMSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArCiAgbGFicyh0aXRsZSA9ICJGaWd1cmUgMTEuIFRvcCAxJSB2cyBib3R0b20gNTAlIHdlYWx0aCBzaGFyZXMgCiAgICAgICBcbiBpbiBXZXN0ZXJuIEV1cm9wZSBhbmQgdGhlIFVTLCAxOTEwLTIwMjAiLCAKICAgICAgIHggPSAiIiwgeSA9ICJTaGFyZSBvZiB0b3RhbCBwZXJzb25hbCB3ZWFsdGggKCUpIiwgY29sb3IgPSAiIiwgbGluZXR5cGUgPSAiIikgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJkb3R0ZWQiLCJzb2xpZCIpKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMjAwMCwgeSA9IDAuNTAsIAogICAgICBsYWJlbCA9IHN0cmluZ3I6OnN0cl93cmFwKCJXZWFsdGggaW5lcXVhbGl0eSBoYXMgYmVlbiByaXNpbmcgYXQgCiAgICAgICAgZGlmZmVyZW50IHNwZWVkcyBhZnRlciBhIGhpc3RvcmljYWwgZGVjbGluZS4gVGhlIGJvdHRvbSA1MCUgaGFzIGFsd2F5cyBiZWVuIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV4dHJlbWVseSBsb3cuIiwgd2lkdGggPSAzMCksIHNpemUgPSAzKQpgYGAKCgotLS0KCiMjIyMgU3RlcCAxLgoKYGBge3J9CmRmX2YxMSAlPiUgcmVuYW1lKCF5ZWFyLCBVU19ib3Q1MCA9IFVTYm90NTAsIFVTX3RvcDEgPSBVU3RvcDEsIAogICAgICAgICAgICAgICAgICBFVV9ib3Q1MCA9IEVVYm90NTAsIEVVX3RvcDEgPSBFVXRvcDEpIApgYGAKCi0tLQoKIyMjIyBTdGVwIDIuIAoKYGBge3Igd2FybmluZyA9IEZBTFNFLCBldmFsPUZBTFNFfQpkZl9mMTEgJT4lIAogIHJlbmFtZSgheWVhciwgVVNfYm90NTAgPSBVU2JvdDUwLCBVU190b3AxID0gVVN0b3AxLCAKICAgICAgICAgRVVfYm90NTAgPSBFVWJvdDUwLCBFVV90b3AxID0gRVV0b3AxKSAlPiUKICBwaXZvdF9sb25nZXIoIXllYXIsIG5hbWVzX3RvID0gYygiZ3JvdXAiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKQpgYGAKCi0tLQoKIyMjIyBTdGVwIDIuIAoKYGBge3Igd2FybmluZyA9IEZBTFNFLCBlY2hvPUZBTFNFfQpkZl9mMTEgJT4lIAogIHJlbmFtZSgheWVhciwgVVNfYm90NTAgPSBVU2JvdDUwLCBVU190b3AxID0gVVN0b3AxLCBFVV9ib3Q1MCA9IEVVYm90NTAsIEVVX3RvcDEgPSBFVXRvcDEpICU+JQogIHBpdm90X2xvbmdlcigheWVhciwgbmFtZXNfdG8gPSBjKCJncm91cCIsIi52YWx1ZSIpLCBuYW1lc19zZXAgPSAiXyIpCmBgYAoKLS0tCgojIyMjIFN0ZXAgMy4KCmBgYHtyIHdhcm5pbmcgPSBGQUxTRSwgZXZhbD1GQUxTRX0KZGZfZjExICU+JSAKICByZW5hbWUoIXllYXIsIFVTX2JvdDUwID0gVVNib3Q1MCwgVVNfdG9wMSA9IFVTdG9wMSwgCiAgICAgICAgIEVVX2JvdDUwID0gRVVib3Q1MCwgRVVfdG9wMSA9IEVVdG9wMSkgJT4lCiAgcGl2b3RfbG9uZ2VyKCF5ZWFyLCBuYW1lc190byA9IGMoImdyb3VwIiwiLnZhbHVlIiksIAogICAgICAgICAgICAgICBuYW1lc19zZXAgPSAiXyIpICU+JQogIHBpdm90X2xvbmdlcigzOjQsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAKYGBgCgotLS0KCiMjIyMgU3RlcCAzLgoKYGBge3Igd2FybmluZyA9IEZBTFNFLCBlY2hvPUZBTFNFfQpkZl9mMTEgJT4lIAogIHJlbmFtZSgheWVhciwgVVNfYm90NTAgPSBVU2JvdDUwLCBVU190b3AxID0gVVN0b3AxLCBFVV9ib3Q1MCA9IEVVYm90NTAsIEVVX3RvcDEgPSBFVXRvcDEpICU+JQogIHBpdm90X2xvbmdlcigheWVhciwgbmFtZXNfdG8gPSBjKCJncm91cCIsIi52YWx1ZSIpLCBuYW1lc19zZXAgPSAiXyIpICU+JQogIHBpdm90X2xvbmdlcigzOjQsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAKYGBgCgotLS0KCmBgYHtyIHdhcm5pbmcgPSBGQUxTRSwgZWNobz1GQUxTRX0KZGZfZjExICU+JSAKICByZW5hbWUoIXllYXIsIFVTX2JvdDUwID0gVVNib3Q1MCwgVVNfdG9wMSA9IFVTdG9wMSwgRVVfYm90NTAgPSBFVWJvdDUwLCBFVV90b3AxID0gRVV0b3AxKSAlPiUKICBwaXZvdF9sb25nZXIoIXllYXIsIG5hbWVzX3RvID0gYygiZ3JvdXAiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKSAlPiUKICBwaXZvdF9sb25nZXIoMzo0LCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gInZhbHVlIikgJT4lCiAgZ2dwbG90KCkgKwogIHN0YXRfc21vb3RoKGFlcyh4ID0geWVhciwgeSA9IHZhbHVlLCBjb2xvciA9IGdyb3VwLCBsaW5ldHlwZSA9IHR5cGUpLCBmb3JtdWxhID0geSB+IHgsIG1ldGhvZCA9ICJsb2VzcyIsIHNwYW4gPSAwLjI1LCBzZSA9IEZBTFNFKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHJvdW5kKHNlcSgxOTEwLCAyMDIwLCBieSA9IDEwKSwxKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICBsYWJzKHRpdGxlID0gIkZpZ3VyZSAxMS4gVG9wIDElIHZzIGJvdHRvbSA1MCUgd2VhbHRoIHNoYXJlcyBcbiBpbiBXZXN0ZXJuIEV1cm9wZSBhbmQgdGhlIFVTLCAxOTEwLTIwMjAiLCAKICAgICAgIHggPSAiIiwgeSA9ICJTaGFyZSBvZiB0b3RhbCBwZXJzb25hbCB3ZWFsdGggKCUpIiwgY29sb3IgPSAiIiwgbGluZXR5cGUgPSAiIikgKwogIHNjYWxlX2xpbmV0eXBlX21hbnVhbCh2YWx1ZXMgPSBjKCJkb3R0ZWQiLCJzb2xpZCIpKSArCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMjAwMCwgeSA9IDAuNTAsIGxhYmVsID0gc3RyaW5ncjo6c3RyX3dyYXAoIldlYWx0aCBpbmVxdWFsaXR5IGhhcyBiZWVuIHJpc2luZyBhdCBkaWZmZXJlbnQgc3BlZWRzIGFmdGVyIGEgaGlzdG9yaWNhbCBkZWNsaW5lLiBUaGUgYm90dG9tIDUwJSBoYXMgYWx3YXlzIGJlZW4gZXh0cmVtZWx5IGxvdy4iLCB3aWR0aCA9IDMwKSwgc2l6ZSA9IDMpCmBgYAoKLS0tCgojIyMgRjg6IFRoZSByaXNlIG9mIHByaXZhdGUgdmVyc3VzIHRoZSBkZWNsaW5lIG9mIHB1YmxpYyB3ZWFsdGggaW4gcmljaCBjb3VudHJpZXMsIDE5NzAtMjAyMCAtIHJlbmFtZSArIHBpdm90ICsgcGl2b3QgKyBmaXQgY3VydmUKCmBgYHtyIGRhdGEtZjgsIGNhc2ggPSBUUlVFfQpkZl9mOCA8LSByZWFkX2V4Y2VsKCJkYXRhL1dJUjIwMjJzLnhsc3giLCBzaGVldCA9ICJkYXRhLUY4Iik7IGRmX2Y4CmBgYAoKLS0tCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBldmFsID0gRkFMU0V9CmRmX2Y4ICU+JSAKICBzZWxlY3QoeWVhciwgR2VybWFueV9wdWJsaWMgPSBHZXJtYW55LCBHZXJtYW55X3ByaXZhdGUgPSAnR2VybWFueSAocHJpdmF0ZSknLCAKICAgICAgICAgU3BhaW5fcHVibGljID0gU3BhaW4sIFNwYWluX3ByaXZhdGUgPSAnU3BhaW4gKHByaXZhdGUpJywgCiAgICAgICAgIEZyYW5jZV9wdWJsaWMgPSBGcmFuY2UsIEZyYW5jZV9wcml2YXRlID0gJ0ZyYW5jZSAocHJpdmF0ZSknLCAKICAgICAgICAgVUtfcHVibGljICA9IFVLLCBVS19wcml2YXRlID0gJ1VLIChwcml2YXRlKScsIAogICAgICAgICBKYXBhbl9wdWJsaWMgPSBKYXBhbiwgSmFwYW5fcHJpdmF0ZSA9ICdKYXBhbiAocHJpdmF0ZSknLCAKICAgICAgICAgTm9yd2F5X3B1YmxpYyA9IE5vcndheSwgTm9yd2F5X3ByaXZhdGUgPSAnTm9yd2F5IChwcml2YXRlKScsCiAgICAgICAgIFVTQV9wdWJsaWMgPSBVU0EsIFVTQV9wcml2YXRlID0gJ1VTQSAocHJpdmF0ZSknKSAlPiUKICBwaXZvdF9sb25nZXIoIXllYXIsIG5hbWVzX3RvID0gYygiY291bnRyeSIsIi52YWx1ZSIpLCBuYW1lc19zZXAgPSAiXyIpICU+JQogIHBpdm90X2xvbmdlcigzOjQsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBnZ3Bsb3QoKSArCiAgc3RhdF9zbW9vdGgoYWVzKHggPSB5ZWFyLCB5ID0gdmFsdWUsIGNvbG9yID0gY291bnRyeSwgbGluZXR5cGUgPSB0eXBlKSwgCiAgICAgICAgICAgICAgc3BhbiA9IDAuMjUsIHNlID0gRkFMU0UsIHNpemU9MC43NSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICBsYWJzKHRpdGxlID0gIkZpZ3VyZSA4LiBUaGUgcmlzZSBvZiBwcml2YXRlIHZlcnN1cyB0aGUgZGVjbGluZSBvZiBwdWJsaWMgCiAgICAgICB3ZWFsdGggaW4gcmljaCBjb3VudHJpZXMsIDE5NzAtMjAyMCIsIAogICAgICAgeCA9ICIiLCB5ID0gIndlYWx0aCBhcyBhcyAlIG9mIG5hdGlvbmFsIGluY29tZSIsIGNvbG9yID0gIiIsIHR5cGUgPSAiIikKYGBgCgotLS0KCiMjIyMgU3RlcCAxCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQpkZl9mOCAlPiUgCiAgc2VsZWN0KHllYXIsIEdlcm1hbnlfcHVibGljID0gR2VybWFueSwgR2VybWFueV9wcml2YXRlID0gJ0dlcm1hbnkgKHByaXZhdGUpJywgCiAgICAgICAgIFNwYWluX3B1YmxpYyA9IFNwYWluLCBTcGFpbl9wcml2YXRlID0gJ1NwYWluIChwcml2YXRlKScsIAogICAgICAgICBGcmFuY2VfcHVibGljID0gRnJhbmNlLCBGcmFuY2VfcHJpdmF0ZSA9ICdGcmFuY2UgKHByaXZhdGUpJywgCiAgICAgICAgIFVLX3B1YmxpYyAgPSBVSywgVUtfcHJpdmF0ZSA9ICdVSyAocHJpdmF0ZSknLCAKICAgICAgICAgSmFwYW5fcHVibGljID0gSmFwYW4sIEphcGFuX3ByaXZhdGUgPSAnSmFwYW4gKHByaXZhdGUpJywgCiAgICAgICAgIE5vcndheV9wdWJsaWMgPSBOb3J3YXksIE5vcndheV9wcml2YXRlID0gJ05vcndheSAocHJpdmF0ZSknLAogICAgICAgICBVU0FfcHVibGljID0gVVNBLCBVU0FfcHJpdmF0ZSA9ICdVU0EgKHByaXZhdGUpJykgCmBgYAoKCi0tLQoKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9CmRmX2Y4ICU+JSAKICBzZWxlY3QoeWVhciwgR2VybWFueV9wdWJsaWMgPSBHZXJtYW55LCBHZXJtYW55X3ByaXZhdGUgPSAnR2VybWFueSAocHJpdmF0ZSknLCAKICAgICAgICAgU3BhaW5fcHVibGljID0gU3BhaW4sIFNwYWluX3ByaXZhdGUgPSAnU3BhaW4gKHByaXZhdGUpJywgCiAgICAgICAgIEZyYW5jZV9wdWJsaWMgPSBGcmFuY2UsIEZyYW5jZV9wcml2YXRlID0gJ0ZyYW5jZSAocHJpdmF0ZSknLCAKICAgICAgICAgVUtfcHVibGljICA9IFVLLCBVS19wcml2YXRlID0gJ1VLIChwcml2YXRlKScsIAogICAgICAgICBKYXBhbl9wdWJsaWMgPSBKYXBhbiwgSmFwYW5fcHJpdmF0ZSA9ICdKYXBhbiAocHJpdmF0ZSknLCAKICAgICAgICAgTm9yd2F5X3B1YmxpYyA9IE5vcndheSwgTm9yd2F5X3ByaXZhdGUgPSAnTm9yd2F5IChwcml2YXRlKScsCiAgICAgICAgIFVTQV9wdWJsaWMgPSBVU0EsIFVTQV9wcml2YXRlID0gJ1VTQSAocHJpdmF0ZSknKQpgYGAKCgoKCi0tLQoKIyMjIyBTdGVwIDIuCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQpkZl9mOCAlPiUgCiAgc2VsZWN0KHllYXIsIEdlcm1hbnlfcHVibGljID0gR2VybWFueSwgR2VybWFueV9wcml2YXRlID0gJ0dlcm1hbnkgKHByaXZhdGUpJywgCiAgICAgICAgIFNwYWluX3B1YmxpYyA9IFNwYWluLCBTcGFpbl9wcml2YXRlID0gJ1NwYWluIChwcml2YXRlKScsIAogICAgICAgICBGcmFuY2VfcHVibGljID0gRnJhbmNlLCBGcmFuY2VfcHJpdmF0ZSA9ICdGcmFuY2UgKHByaXZhdGUpJywgCiAgICAgICAgIFVLX3B1YmxpYyAgPSBVSywgVUtfcHJpdmF0ZSA9ICdVSyAocHJpdmF0ZSknLCAKICAgICAgICAgSmFwYW5fcHVibGljID0gSmFwYW4sIEphcGFuX3ByaXZhdGUgPSAnSmFwYW4gKHByaXZhdGUpJywgCiAgICAgICAgIE5vcndheV9wdWJsaWMgPSBOb3J3YXksIE5vcndheV9wcml2YXRlID0gJ05vcndheSAocHJpdmF0ZSknLAogICAgICAgICBVU0FfcHVibGljID0gVVNBLCBVU0FfcHJpdmF0ZSA9ICdVU0EgKHByaXZhdGUpJykgJT4lCiAgcGl2b3RfbG9uZ2VyKCF5ZWFyLCBuYW1lc190byA9IGMoImNvdW50cnkiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKSAKYGBgCgoKLS0tCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQpkZl9mOCAlPiUgCiAgc2VsZWN0KHllYXIsIEdlcm1hbnlfcHVibGljID0gR2VybWFueSwgR2VybWFueV9wcml2YXRlID0gJ0dlcm1hbnkgKHByaXZhdGUpJywgCiAgICAgICAgIFNwYWluX3B1YmxpYyA9IFNwYWluLCBTcGFpbl9wcml2YXRlID0gJ1NwYWluIChwcml2YXRlKScsIAogICAgICAgICBGcmFuY2VfcHVibGljID0gRnJhbmNlLCBGcmFuY2VfcHJpdmF0ZSA9ICdGcmFuY2UgKHByaXZhdGUpJywgCiAgICAgICAgIFVLX3B1YmxpYyAgPSBVSywgVUtfcHJpdmF0ZSA9ICdVSyAocHJpdmF0ZSknLCAKICAgICAgICAgSmFwYW5fcHVibGljID0gSmFwYW4sIEphcGFuX3ByaXZhdGUgPSAnSmFwYW4gKHByaXZhdGUpJywgCiAgICAgICAgIE5vcndheV9wdWJsaWMgPSBOb3J3YXksIE5vcndheV9wcml2YXRlID0gJ05vcndheSAocHJpdmF0ZSknLAogICAgICAgICBVU0FfcHVibGljID0gVVNBLCBVU0FfcHJpdmF0ZSA9ICdVU0EgKHByaXZhdGUpJykgJT4lCiAgcGl2b3RfbG9uZ2VyKCF5ZWFyLCBuYW1lc190byA9IGMoImNvdW50cnkiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKQpgYGAKCi0tLQoKIyMjIyBTdGVwIDMuCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQpkZl9mOCAlPiUgCiAgc2VsZWN0KHllYXIsIEdlcm1hbnlfcHVibGljID0gR2VybWFueSwgR2VybWFueV9wcml2YXRlID0gJ0dlcm1hbnkgKHByaXZhdGUpJywgCiAgICAgICAgIFNwYWluX3B1YmxpYyA9IFNwYWluLCBTcGFpbl9wcml2YXRlID0gJ1NwYWluIChwcml2YXRlKScsIAogICAgICAgICBGcmFuY2VfcHVibGljID0gRnJhbmNlLCBGcmFuY2VfcHJpdmF0ZSA9ICdGcmFuY2UgKHByaXZhdGUpJywgCiAgICAgICAgIFVLX3B1YmxpYyAgPSBVSywgVUtfcHJpdmF0ZSA9ICdVSyAocHJpdmF0ZSknLCAKICAgICAgICAgSmFwYW5fcHVibGljID0gSmFwYW4sIEphcGFuX3ByaXZhdGUgPSAnSmFwYW4gKHByaXZhdGUpJywgCiAgICAgICAgIE5vcndheV9wdWJsaWMgPSBOb3J3YXksIE5vcndheV9wcml2YXRlID0gJ05vcndheSAocHJpdmF0ZSknLAogICAgICAgICBVU0FfcHVibGljID0gVVNBLCBVU0FfcHJpdmF0ZSA9ICdVU0EgKHByaXZhdGUpJykgJT4lCiAgcGl2b3RfbG9uZ2VyKCF5ZWFyLCBuYW1lc190byA9IGMoImNvdW50cnkiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKSAlPiUKICBwaXZvdF9sb25nZXIoMzo0LCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gInZhbHVlIikKYGBgCgotLS0KCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBlY2hvPUZBTFNFfQpkZl9mOCAlPiUgCiAgc2VsZWN0KHllYXIsIEdlcm1hbnlfcHVibGljID0gR2VybWFueSwgR2VybWFueV9wcml2YXRlID0gJ0dlcm1hbnkgKHByaXZhdGUpJywgCiAgICAgICAgIFNwYWluX3B1YmxpYyA9IFNwYWluLCBTcGFpbl9wcml2YXRlID0gJ1NwYWluIChwcml2YXRlKScsIAogICAgICAgICBGcmFuY2VfcHVibGljID0gRnJhbmNlLCBGcmFuY2VfcHJpdmF0ZSA9ICdGcmFuY2UgKHByaXZhdGUpJywgCiAgICAgICAgIFVLX3B1YmxpYyAgPSBVSywgVUtfcHJpdmF0ZSA9ICdVSyAocHJpdmF0ZSknLCAKICAgICAgICAgSmFwYW5fcHVibGljID0gSmFwYW4sIEphcGFuX3ByaXZhdGUgPSAnSmFwYW4gKHByaXZhdGUpJywgCiAgICAgICAgIE5vcndheV9wdWJsaWMgPSBOb3J3YXksIE5vcndheV9wcml2YXRlID0gJ05vcndheSAocHJpdmF0ZSknLAogICAgICAgICBVU0FfcHVibGljID0gVVNBLCBVU0FfcHJpdmF0ZSA9ICdVU0EgKHByaXZhdGUpJykgJT4lCiAgcGl2b3RfbG9uZ2VyKCF5ZWFyLCBuYW1lc190byA9IGMoImNvdW50cnkiLCIudmFsdWUiKSwgbmFtZXNfc2VwID0gIl8iKSAlPiUKICBwaXZvdF9sb25nZXIoMzo0LCBuYW1lc190byA9ICJ0eXBlIiwgdmFsdWVzX3RvID0gInZhbHVlIikgCmBgYAoKLS0tCgojIyMjIFN0ZXAgMy4gRmluYWwgU3RlcAoKYGBge3IgZXZhbD1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGZfZjggJT4lIAogIHNlbGVjdCh5ZWFyLCBHZXJtYW55X3B1YmxpYyA9IEdlcm1hbnksIEdlcm1hbnlfcHJpdmF0ZSA9ICdHZXJtYW55IChwcml2YXRlKScsIAogICAgICAgICBTcGFpbl9wdWJsaWMgPSBTcGFpbiwgU3BhaW5fcHJpdmF0ZSA9ICdTcGFpbiAocHJpdmF0ZSknLCAKICAgICAgICAgRnJhbmNlX3B1YmxpYyA9IEZyYW5jZSwgRnJhbmNlX3ByaXZhdGUgPSAnRnJhbmNlIChwcml2YXRlKScsIAogICAgICAgICBVS19wdWJsaWMgID0gVUssIFVLX3ByaXZhdGUgPSAnVUsgKHByaXZhdGUpJywgCiAgICAgICAgIEphcGFuX3B1YmxpYyA9IEphcGFuLCBKYXBhbl9wcml2YXRlID0gJ0phcGFuIChwcml2YXRlKScsIAogICAgICAgICBOb3J3YXlfcHVibGljID0gTm9yd2F5LCBOb3J3YXlfcHJpdmF0ZSA9ICdOb3J3YXkgKHByaXZhdGUpJywKICAgICAgICAgVVNBX3B1YmxpYyA9IFVTQSwgVVNBX3ByaXZhdGUgPSAnVVNBIChwcml2YXRlKScpICU+JQogIHBpdm90X2xvbmdlcigheWVhciwgbmFtZXNfdG8gPSBjKCJjb3VudHJ5IiwiLnZhbHVlIiksIG5hbWVzX3NlcCA9ICJfIikgJT4lCiAgcGl2b3RfbG9uZ2VyKDM6NCwgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQogIGdncGxvdCgpICsKICBzdGF0X3Ntb290aChhZXMoeCA9IHllYXIsIHkgPSB2YWx1ZSwgY29sb3IgPSBjb3VudHJ5LCBsaW5ldHlwZSA9IHR5cGUpLCAKICAgICAgICAgICAgICBmb3JtdWxhID0geX54LCBtZXRob2QgPSAibG9lc3MiLCBzcGFuID0gMC4yNSwgc2UgPSBGQUxTRSwgc2l6ZT0wLjc1KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDguIFRoZSByaXNlIG9mIHByaXZhdGUgdmVyc3VzIHRoZSBkZWNsaW5lIG9mIHB1YmxpYyB3ZWFsdGggCiAgICAgICBcbmluIHJpY2ggY291bnRyaWVzLCAxOTcwLTIwMjAiLCAKICAgICAgIHggPSAiIiwgeSA9ICJ3ZWFsdGggYXMgYXMgJSBvZiBuYXRpb25hbCBpbmNvbWUiLCBjb2xvciA9ICIiLCB0eXBlID0gIiIpCmBgYAoKCi0tLQoKYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0KZGZfZjggJT4lIAogIHNlbGVjdCh5ZWFyLCBHZXJtYW55X3B1YmxpYyA9IEdlcm1hbnksIEdlcm1hbnlfcHJpdmF0ZSA9ICdHZXJtYW55IChwcml2YXRlKScsIAogICAgICAgICBTcGFpbl9wdWJsaWMgPSBTcGFpbiwgU3BhaW5fcHJpdmF0ZSA9ICdTcGFpbiAocHJpdmF0ZSknLCAKICAgICAgICAgRnJhbmNlX3B1YmxpYyA9IEZyYW5jZSwgRnJhbmNlX3ByaXZhdGUgPSAnRnJhbmNlIChwcml2YXRlKScsIAogICAgICAgICBVS19wdWJsaWMgID0gVUssIFVLX3ByaXZhdGUgPSAnVUsgKHByaXZhdGUpJywgCiAgICAgICAgIEphcGFuX3B1YmxpYyA9IEphcGFuLCBKYXBhbl9wcml2YXRlID0gJ0phcGFuIChwcml2YXRlKScsIAogICAgICAgICBOb3J3YXlfcHVibGljID0gTm9yd2F5LCBOb3J3YXlfcHJpdmF0ZSA9ICdOb3J3YXkgKHByaXZhdGUpJywKICAgICAgICAgVVNBX3B1YmxpYyA9IFVTQSwgVVNBX3ByaXZhdGUgPSAnVVNBIChwcml2YXRlKScpICU+JQogIHBpdm90X2xvbmdlcigheWVhciwgbmFtZXNfdG8gPSBjKCJjb3VudHJ5IiwiLnZhbHVlIiksIG5hbWVzX3NlcCA9ICJfIikgJT4lCiAgcGl2b3RfbG9uZ2VyKDM6NCwgbmFtZXNfdG8gPSAidHlwZSIsIHZhbHVlc190byA9ICJ2YWx1ZSIpICU+JQogIGdncGxvdCgpICsKICBzdGF0X3Ntb290aChhZXMoeCA9IHllYXIsIHkgPSB2YWx1ZSwgY29sb3IgPSBjb3VudHJ5LCBsaW5ldHlwZSA9IHR5cGUpLCAKICAgICAgICAgICAgICBmb3JtdWxhID0geX54LCBtZXRob2QgPSAibG9lc3MiLCBzcGFuID0gMC4yNSwgc2UgPSBGQUxTRSwgc2l6ZT0wLjc1KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSAxKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDguIFRoZSByaXNlIG9mIHByaXZhdGUgdmVyc3VzIHRoZSBkZWNsaW5lIG9mIHB1YmxpYyB3ZWFsdGggCiAgICAgICBcbmluIHJpY2ggY291bnRyaWVzLCAxOTcwLTIwMjAiLCAKICAgICAgIHggPSAiIiwgeSA9ICJ3ZWFsdGggYXMgYXMgJSBvZiBuYXRpb25hbCBpbmNvbWUiLCBjb2xvciA9ICIiLCB0eXBlID0gIiIpCmBgYAoKLS0tCgojIyMgRjE1OiBQZXIgY2FwaXRhIGVtaXNzaW9ucyBhY3Jpc3MgdGhlIHdvcmxkLCAyMDE5IC0gYWRkIHJvdyBuYW1lcyArIGRvZGdlCgpgYGB7ciBkYXRhLWYxNSwgY2FzaCA9IFRSVUV9CmRmX2YxNSA8LSByZWFkX2V4Y2VsKCJkYXRhL1dJUjIwMjJzLnhsc3giLCBzaGVldCA9ICJkYXRhLUYxNSIpOyBkZl9mMTUKYGBgCgotLS0KCmBgYHtyIGV2YWwgPSBGQUxTRX0KZGZfZjE1ICU+JSBtdXRhdGUocmVnaW9uID0gcmVwKHJlZ2lvbldJRFshaXMubmEocmVnaW9uV0lEKV0sIGVhY2ggPSAzKSkgJT4lCiAgc2VsZWN0KHJlZ2lvbiwgZ3JvdXAsIHRjYXApICU+JQogIGdncGxvdChhZXMoeCA9IHJlZ2lvbiwgeSA9IHRjYXAsIGZpbGwgPSBncm91cCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsgCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcCh4LCB3aWR0aCA9IDEwKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDE1IFBlciBjYXBpdGEgZW1pc3Npb25zIGFjcm9zcyB0aGUgd29ybGQsIDIwMTkiLCAKICAgICAgIHggPSAiIiwgeSA9ICJ0b25uZXMgb2YgQ08yZSBwZXIgcGVyc29uIHBlciB5ZWFyIiwgZmlsbCA9ICIiKQpgYGAKCgotLS0KCmBgYHtyIGVjaG8gPSBGQUxTRX0KZGZfZjE1ICU+JSBtdXRhdGUocmVnaW9uID0gcmVwKHJlZ2lvbldJRFshaXMubmEocmVnaW9uV0lEKV0sIGVhY2ggPSAzKSkgJT4lCiAgc2VsZWN0KHJlZ2lvbiwgZ3JvdXAsIHRjYXApICU+JQogIGdncGxvdChhZXMoeCA9IHJlZ2lvbiwgeSA9IHRjYXAsIGZpbGwgPSBncm91cCkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpICsgCiAgc2NhbGVfeF9kaXNjcmV0ZShsYWJlbHMgPSBmdW5jdGlvbih4KSBzdHJpbmdyOjpzdHJfd3JhcCh4LCB3aWR0aCA9IDEwKSkgKwogIGxhYnModGl0bGUgPSAiRmlndXJlIDE1IFBlciBjYXBpdGEgZW1pc3Npb25zIGFjcm9zcyB0aGUgd29ybGQsIDIwMTkiLCAKICAgICAgIHggPSAiIiwgeSA9ICJ0b25uZXMgb2YgQ08yZSBwZXIgcGVyc29uIHBlciB5ZWFyIiwgZmlsbCA9ICIiKQpgYGAKCgojIyBFREEgV29ya2Zsb3cKCiMjIyBFREEgU3RlcCAwCgoxLiBDaG9vc2UgYW5kIGNsYXJpZnkgYSB0b3BpYyB0byBzdHVkeS4KMi4gTGlzdCBxdWVzdGlvbnMgdG8gc3R1ZHkKMy4gRmluZCBkYXRhOgogIC0gbGluayB0byBkYXRhIHdpdGggYSB1cmw6IHVuaXZlcnNhbCByZXNvdXJjZSBsb2NhdG9yIGluIGEgd2VicGFnZQogIC0gZG93bmxvYWQgZGF0YSBpbiBjc3YsIEV4Y2VsLCBldGMuCgpSZXBlYXQgdGhlIHByb2Nlc3MgZHVyaW5nIHlvdXIgRURBLgoKCiFbaW1hZ2VdKGRhdGEvZGF0YS1zY2llbmNlLnBuZykKCiMjIyBFREEgYnkgUiBTdHVkaW86IFN0ZXAgMQoKSW4gUlN0dWRpbywKCjEuMS4gUHJvamVjdAoKICAqIENyZWF0ZSBhIG5ldyBwcm9qZWN0OiBGaWxlID4gTmV3IFByb2plY3Q7IG9yICAKICAqIE9wZW4gYSBwcm9qZWN0OiBGaWxlID4gT3BlbiBQcm9qZWN0LCBPcGVuIFByb2plY3QgaW4gTmV3IFNlc3Npb24sIE9wZW4gUmVjZW50IFByb2plY3QgIAogICAgLSBJdCBpcyBlYXNpZXIgdG8gZmluZCBhbiBleGlzdGluZyBwcm9qZWN0IGZyb206IEZpbGUgPiBSZWNlbnQgUHJvamVjdCAKICAqIF9DaGVjayB0aGVyZSBpcyBhIGZpbGUgYHByb2plY3RfbmFtZS5ScHJvamAgaW4geW91ciBwcm9qZWN0IGZvbGRlciAoZGlyZWN0b3J5KV8KCiAKMS4yLiBkYXRhIGZvbGRlciAoZGlyZWN0b3J5KSBgZGF0YWAKCiAgKiBDcmVhdGUgYSBkYXRhIGZvbGRlcjogUHJlc3MgTmV3IEZvbGRlciBhdCB0aGUgcmlnaHQgYm90dG9tIHBhbmU7IG9yIAogICogQ29uZmlybSB0aGUgZGF0YSBmb2xkZXIgcHJldmlvdXNseSBjcmVhdGVkOiBQcmVzcyBGaWxlcyBhdCB0aGUgcmlnaHQgYm90dG9tIHBhbmUKICAqIF9JZiB5b3UgZm9sbG93IDEsIHRoZSBkYXRhIGZvbGRlciBleGlzdHMgaW4geW91ciBwcm9qZWN0IGZvbGRlcl8KCiAKMS4zLiBNb3ZlIChvciBjb3B5KSBkYXRhIGZvciB0aGUgcHJvamVjdCB0byB0aGUgZGF0YSBmb2xkZXIKCiAgKiBJZiB5b3UgZG93bmxvYWRlZCB0aGUgZGF0YSwgaXQgaXMgaW4geW91ciBEb3dubG9hZCBmb2xkZXIuIE1vdmUgaXQgdG8gYGRhdGFgLgogICogX0NoZWNrIGluIHlvdXIgUlN0dWRpbyB0aGF0IHlvdXIgZGF0YSBpcyBpbiBgZGF0YWA6IFByZXNzIEZpbGVzIGF0IHRoZSByaWdodCBib3R0b20gcGFuZSBhbmQgY2xpY2sgYGRhdGFgLCB0aGUgZGF0YSBmb2xkZXIuXwogIAoKLS0tCgojIyMgRURBIGJ5IFIgU3R1ZGlvOiBTdGVwIDIKCjIuMS4gUHJvamVjdCBOb3RlYm9vazogTWVtbwoKICAtIENyZWF0ZSBhbiBSIE5vdGVib29rOiBGaWxlID4gTmV3IEZpbGUgPiBSIE5vdGVib29rCiAgCiAgICArIFlvdSBjYW4gdXNlIFIgTm90ZWJvb2sgdGVtcGxhdGUgaW4gTW9vZGxlIGJ5IG1vdmluZyB0aGUgdGVtcGxhdGUgKHRlbXBsYXRlLlJtZCBvciB0ZW1wbGF0ZS5uYi5SbWQpIGZpbGUgaW4geW91ciBwcm9qZWN0IGZvbGRlciBvciBjb3B5IGFuZCBwYXN0ZSB0aGUgdGV4dCBmaWxlIGludG8geW91ciBuZXcgUiBOb3RlYm9vay4KICAgICsgSWYgeW91IHVzZSB0ZW1wbGF0ZS5uYi5SbWQgKFIgTm90ZWJvb2sgRmlsZSksIGNob29zZSBPcGVuIGluIEVkaXRvci4KICAgIAogIC0gQWRkIGRlc2NyaXB0aXZlIHRpdGxlLiAKICAKMi4yLiBTZXR1cCBDb2RlIENodW5rIAoKICAtIENyZWF0ZSBhIGNvZGUgY2h1bmsgYW5kIGFkZCBwYWNrYWdlcyB0byB1c2UgaW4gdGhlIHByb2plY3QgYW5kIFJVTiB0aGUgY29kZS4KICAKICAgICAgKyBsaWJyYXJ5KHRpZHl2ZXJzZSkKICAgICAgKyBsaWJyYXJ5KFdESSkKICAgICAgKyBvciBhbnkgb3RoZXIgcGFja2FnZXMKCi0tLQoKMi4zLiBDaG9vc2UgYFNvdXJjZWAgb3IgYFZpc3VhbGAgZWRpdG9yIG1vZGUsIGFuZCBzdGFydCBlZGl0aW5nIFByb2plY3QgTm90ZWJvb2sKCiAgLSBTZXQgdXAgSGVhZGluZ3Mgc3VjaCBhczogQWJvdXQsIERhdGEsIEFuYWx5c2lzIGFuZCBWaXN1YWxpemF0aW9ucywgQ29uY2x1c2lvbnMKICAtIFVuZGVyIEFib3V0IG9yIERhdGEsIHBhc3RlIHVybCBvZiB0aGUgc2l0ZXMgYW5kL29yIHRoZSBkYXRhCgogICAgICArIGVnLiBXb3JsZCBEZXZlbG9wbWVudCBJbmRpY2F0b3I6CiAgICAgIGh0dHBzOi8vZGF0YXRvcGljcy53b3JsZGJhbmsub3JnL3dvcmxkLWRldmVsb3BtZW50LWluZGljYXRvcnMvKQogICAgICArIGVnLiBQdWJsaWMgZXhwZW5kaXR1cmUgb24gZWR1Y2F0aW9uOgogICAgICBodHRwczovL2RhdGEudW4ub3JnL19Eb2NzL1NZQi9DU1YvU1lCNjVfMjQ1XzIwMjIwOV9QdWJsaWMlCiAgICAgIDIwZXhwZW5kaXR1cmUlMjBvbiUyMGVkdWNhdGlvbi5jc3YpCgoKMi40LiBFZGl0IGEgbmV3IGZpbGUgYnkgc2F2aW5nIGFzIGZvciBhIHJlcG9ydAoKICAtIEZpbGUgPiBTYXZlIEFzLi4uCgotLS0KCiMjIyBFREEgYnkgUiBTdHVkaW86IFN0ZXAgMyAtIEltcG9ydGluZyBEYXRhCgpBc3NpZ24gYSBuYW1lIHlvdSBjYW4gcmVjYWxsIGVhc2lseSB3aGVuIHlvdSBpbXBvcnQgZGF0YS4gWW91IG1heSBuZWVkIHRvIHJlbG9hZCB0aGUgZGF0YSB3aXRoIG9wdGlvbnMuCgozLjEuIFVzZSBhIHBhY2thZ2U6CgogICogV0RJLCB3aXIsIGV1cm9zdGF0LCBldGMvCiAgKiBgd2RpX3Nob3J0bmFtZSA8LSBXREkoaW5kaWNhdG9yID0gImluZGljYXRvcidzIG5hbWUiLCAuLi4gKQogICogU3RvcmUgdGhlIGRhdGEgYW5kIHVzZSBpdDogYHdyaXRlX2Nzdih3ZGlfc2hvcnRuYW1lLCAiZGF0YS93ZGlfc2hvcnRuYW1lLmNzdiIpYAogICogYHdkaV9zaG9ydG5hbWUgPC0gcmVhZF9jc3YoImRhdGEvd2RpX3Nob3J0bmFtZS5jc3YiKWAKICAKMy4yLiBVc2UgYHJlYWRyYCB0byByZWFkIGZyb20gYGRhdGFgLCB5b3VyIGRhdGEgZm9sZGVyCgogICogYGRmMV9zaG9ydG5hbWUgPC0gcmVhZF9jc3YoImRhdGEvZmlsZV9uYW1lLmNzdiIpYAoKLS0tCgozLjMuIFVzZSBgcmVhZHJgIHRvIHJlYWQgdXNpbmcgdGhlIHVybCBvZiB0aGUgZGF0YQoKICAqIGBkZjJfc2hvcnRuYW1lIDwtIHJlYWRfY3N2KCJ1cmxfb2ZfdGhlX2RhdGEiKWAKICAqIFN0b3JlIHRoZSBkYXRhIGFuZCB1c2UgaXQ6IGB3cml0ZV9jc3YoZGYyX3Nob3J0bmFtZSwgImRhdGEvZGYyX3Nob3J0bmFtZS5jc3YiKWAKICAqIGBkZjJfc2hvcnRuYW1lIDwtIHJlYWRfY3N2KCJkYXRhL2RmMl9zaG9ydG5hbWUuY3N2IilgCiAgCjMuNS4gVXNlIGByZWFkeGxgIHRvIHJlYWQgRXhjZWwgZGF0YS4gQWRkIGBsaWJyYXJ5KHJlYWR4bClgIGluIHRoZSBzZXR1cCBhbmQgcnVuLgoKICAqIGBkZjQgPC0gcmVhZF9leGNlbCgiZGF0YS9maWxlX25hbWUueGxzeCIsIHNoZWV0ID0gMSlgCiAgClJlZmVyZW5jZXM6IENoZWF0IFNoZWV0IC0gYHJlYWRyYCwgW3JlYWRyXShodHRwczovL3JlYWRyLnRpZHl2ZXJzZS5vcmcpLCBbcmVhZHhsXShodHRwczovL3JlYWR4bC50aWR5dmVyc2Uub3JnKQoKCi0tLQoKIyMjIEVEQSBieSBSIFN0dWRpbzogU3RlcCA0IC0gRGF0YSBUcmFzbmZvcm1hdGlvbgoKNC4xLiBMb29rIGF0IHRoZSBkYXRhOiBzdXBwb3NlIGBkZmAgaXMgdGhlIGRhdGEgZnJhbWUKCiAgKiBJdCBpcyBhIGdvb2Qgb3B0aW9uIHRvIGNoYW5nZSBpbnRvIGEgdGliYmxlOiBgZHQgPC0gYXNfdGliYmxlKGRmKWAKICAqIGBoZWFkKGRmKWAsIGBzdHIoZGYpYCwgYHN1bW1hcnkoZGYpYCwgYGR0YCwgYGdsaW1wc2UoZHQpYAoKNC4yLiBMb29rIGF0IGVhY2ggdmFyaWFibGUKCiAgKiBjYXRlZ29yaWNhbD8gbnVtZXJpY2FsPyAKICAqIGZhY3Rvcj8gLSBbZm9yY2F0c10oaHR0cHM6Ly9mb3JjYXRzLnRpZHl2ZXJzZS5vcmcpCiAgCjQuMy4gVmFyaWF0aW9uIG9mIGVhY2ggZGF0YTogc3VwcG9zZSBgeDFgIGlzIGEgY29sdW1uIG5hbWUuCgogICogYGRmICU+JSBnZ3Bsb3QoKSArIGdlb21faGlzdG9ncmFtKGFlcyh4MSksIGJpbnMgPSAzMClgCiAgKiBgZGYgJT4lIGRyb3BfbmEoeDEpYDogc2VlIHRoZSByb3dzIHdpdGggYSB2YWx1ZSBpbiBgeDFgLiBJZiB0aGUgdmFsdWUgaXMgTkEsIHRoZSByb3cgaXMgbm90IHNob3duLgogIAogICAgLSBgZGZfd29fbmEgPC0gZGYgJT4lIGRyb3BfbmEoeDEpYCBpZiB5b3Ugd2FudCB0byB1c2Ugb25seSB0aGUgcm93cyB3aXRob3V0IE5BIGluIGB4MWAKICAgIAotLS0KCjQuNC4gVXNlIGBkcHlscmAgYW5kIGB0aWR5cmAgdG8gY2hhbmdlIGNvbHVtbiBuYW1lcywgdGlkeSBkYXRhLCBhbmQvb3Igc3VtbWFyaXplIGRhdGEKCiAgKiBgcmVuYW1lYCwgYHNlbGVjdGAsIGBmaWx0ZXJgLCBgYXJyYW5nZWAsIGBtdXRhdGVgLCBgcGl2b3RfbG9uZ2VyKClgLCBgcGl2b3Rfd2lkZXIoKWAsIGBncm91cF9ieWAgYW5kIGBzdW1tYXJpemVgCgoKUmVmZXJlbmNlczogQ2hlYXQgU2hlZXQgLSBgZHBseXJgIGFuZCBgdGlkeXJgLCBbZHBseXJdKGh0dHBzOi8vZHBseXIudGlkeXZlcnNlLm9yZyksIFt0aWR5cl0oaHR0cHM6Ly90aWR5ci50aWR5dmVyc2Uub3JnKQoKLS0tCgojIyMgRURBIGJ5IFIgU3R1ZGlvOiBTdGVwIDUgLSBWaXN1YWxpemUgRGF0YQoKNS4xLiBJbiBjb21iaW5hdGlvbiB3aXRoIFN0YXAgNCAtIGRhdGEgdHJhbnNmb3JtYXRpb24sIHRyeSB2YXJpb3VzIGRhdGEgdmlzdWFsaXphdGlvbi4KCiAgKiBXaGF0IHR5cGUgb2YgdmFyaWF0aW9uIG9jY3VycyB3aXRoaW4gbXkgdmFyaWFibGVzPwogICogV2hhdCB0eXBlIG9mIGNvdmFyaWF0aW9uIG9jY3VycyBiZXR3ZWVuIG15IHZhcmlhYmxlcz8KCgo1LjIuIEtlZXAgYSByZWNvcmQgb2Ygd2hhdCB5b3UgY2FuIG9ic2VydmUgYnkgdGhlIHZpc3VhbGl6YXRpb24KCjUuMy4gRWRpdCB0aGUgbGlzdCBvZiBxdWVzdGlvbnMgYnkgYWRkaW5nIG9yIHBvbGlzaGluZwoKNS40LiBTZWxlY3Qgc2V2ZXJhbCBpbmZvcm1hdGl2ZSBjaGFydCBhbmQgYWRkIG9wdGlvbnMKCjUuNS4gTG9vayBhdCBleGFtcGxlcyBmcm9tIHRoZSB0ZXh0Ym9va3Mgb3IgdGVhY2hpbmcgc2l0ZSB0byBoYXZlIGJldHRlciB2aXN1YWxpemF0aW9uCgpSZWZlcmVuY2VzOiBDaGVhdCBTaGVldCAtIGBnZ3Bsb3QyYCBbZ2dwbG90Ml0oaHR0cHM6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcpLCBbZ2dwbG90MiBib29rXShodHRwczovL2dncGxvdDItYm9vay5vcmcpCgotLS0KCiMjIyBFREEgYnkgUiBTdHVkaW86IFN0ZXAgNiAtIENvbmNsdXNpb25zIGFuZCBRdWVzdGlvbnMgZm9yIEZ1cnRoZXIgU3R1ZHkKCjEuIEVEQSBpcyBhbiBpdGVyYXRpdmUgY3ljbGUgdGhhdCBoZWxwcyB5b3UgdW5kZXJzdGFuZCB3aGF0IHlvdXIgZGF0YSBzYXlzLiBXaGVuIHlvdSBkbyBFREEsIHlvdToKCjIuIEdlbmVyYXRlIHF1ZXN0aW9ucyBhYm91dCB5b3VyIGRhdGEKCjMuIFNlYXJjaCBmb3IgYW5zd2VycyBieSB2aXN1YWxpc2luZywgdHJhbnNmb3JtaW5nLCBhbmQvb3IgbW9kZWxpbmcgeW91ciBkYXRhCgpVc2Ugd2hhdCB5b3UgbGVhcm4gdG8gcmVmaW5lIHlvdXIgcXVlc3Rpb25zIGFuZC9vciBnZW5lcmF0ZSBuZXcgcXVlc3Rpb25zCgpFREEgaXMgYW4gaW1wb3J0YW50IHBhcnQgb2YgYW55IGRhdGEgYW5hbHlzaXMuIFlvdSBjYW4gdXNlIEVEQSB0byBtYWtlIGRpc2NvdmVyaWVzIGFib3V0IHRoZSB3b3JsZDsgb3IgeW91IGNhbiB1c2UgRURBIHRvIGVuc3VyZSB0aGUgcXVhbGl0eSBvZiB5b3VyIGRhdGEsIGFza2luZyBxdWVzdGlvbnMgYWJvdXQgd2hldGhlciB0aGUgZGF0YSBtZWV0cyB5b3VyIHN0YW5kYXJkcyBvciBub3QuCgotLS0KCiMjIyBFeGFtcGxlOiBXREkKCiogR292ZXJubWVudCBleHBlbmRpdHVyZSBvbiBlZHVjYXRpb24sIHRvdGFsICglIG9mIEdEUCkKCiAgLSBodHRwczovL2RhdGEud29ybGRiYW5rLm9yZy9pbmRpY2F0b3IvU0UuWFBELlRPVEwuR0QuWlMKICAKKiBJRDogU0UuWFBELlRPVEwuR0QuWlMKCi0tLQoKIyMjIEV4YW1wbGU6IFdJUjIwMjIKCmBgYHtyIHdhcm5pbmc9RkFMU0UsIGVjaG89RkFMU0V9CmRmX2Y4ICU+JSAKICBzZWxlY3QoeWVhciwgR2VybWFueV9wdWJsaWMgPSBHZXJtYW55LCBHZXJtYW55X3ByaXZhdGUgPSAnR2VybWFueSAocHJpdmF0ZSknLCAKICAgICAgICAgU3BhaW5fcHVibGljID0gU3BhaW4sIFNwYWluX3ByaXZhdGUgPSAnU3BhaW4gKHByaXZhdGUpJywgCiAgICAgICAgIEZyYW5jZV9wdWJsaWMgPSBGcmFuY2UsIEZyYW5jZV9wcml2YXRlID0gJ0ZyYW5jZSAocHJpdmF0ZSknLCAKICAgICAgICAgVUtfcHVibGljICA9IFVLLCBVS19wcml2YXRlID0gJ1VLIChwcml2YXRlKScsIAogICAgICAgICBKYXBhbl9wdWJsaWMgPSBKYXBhbiwgSmFwYW5fcHJpdmF0ZSA9ICdKYXBhbiAocHJpdmF0ZSknLCAKICAgICAgICAgTm9yd2F5X3B1YmxpYyA9IE5vcndheSwgTm9yd2F5X3ByaXZhdGUgPSAnTm9yd2F5IChwcml2YXRlKScsCiAgICAgICAgIFVTQV9wdWJsaWMgPSBVU0EsIFVTQV9wcml2YXRlID0gJ1VTQSAocHJpdmF0ZSknKSAlPiUKICBwaXZvdF9sb25nZXIoIXllYXIsIG5hbWVzX3RvID0gYygiY291bnRyeSIsIi52YWx1ZSIpLCBuYW1lc19zZXAgPSAiXyIpICU+JQogIHBpdm90X2xvbmdlcigzOjQsIG5hbWVzX3RvID0gInR5cGUiLCB2YWx1ZXNfdG8gPSAidmFsdWUiKSAlPiUKICBnZ3Bsb3QoKSArCiAgc3RhdF9zbW9vdGgoYWVzKHggPSB5ZWFyLCB5ID0gdmFsdWUsIGNvbG9yID0gY291bnRyeSwgbGluZXR5cGUgPSB0eXBlKSwgZm9ybXVsYSA9IHl+eCwgbWV0aG9kID0gImxvZXNzIiwgc3BhbiA9IDAuMjUsIHNlID0gRkFMU0UsIHNpemU9MC43NSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gMSkpICsKICBsYWJzKHRpdGxlID0gIkZpZ3VyZSA4LiBUaGUgcmlzZSBvZiBwcml2YXRlIHZlcnN1cyB0aGUgZGVjbGluZSBvZiBwdWJsaWMgd2VhbHRoIFxuaW4gcmljaCBjb3VudHJpZXMsIDE5NzAtMjAyMCIsIAogICAgICAgeCA9ICIiLCB5ID0gIndlYWx0aCBhcyBhcyAlIG9mIG5hdGlvbmFsIGluY29tZSIsIGNvbG9yID0gIiIsIHR5cGUgPSAiIikKYGBgCgojIyBUaGUgV2VlayBGaXZlIEFzc2lnbm1lbnQgKGluIE1vb2RsZSkKCioqYHRpZHlyYCBhbmQgV0lSMjAyMioqCgoqIENyZWF0ZSBhbiBSIE5vdGVib29rIG9mIGEgRGF0YSBBbmFseXNpcyBjb250YWluaW5nIHRoZSBmb2xsb3dpbmcgYW5kIHN1Ym1pdCB0aGUgcmVuZGVyZWQgSFRNTCBmaWxlIChlZy4gYGEzXzEyMzQ1Ni5uYi5odG1sYCAgYnkgcmVwbGFjaW5nIDEyMzQ1NiB3aXRoIHlvdXIgSUQpCiAgMS4gY3JlYXRlIGFuIFIgTm90ZWJvb2sgdXNpbmcgdGhlIFIgTm90ZWJvb2sgVGVtcGxhdGUgaW4gTW9vZGxlLCAgc2F2ZSBhcyBgYTNfMTIzNDU2LlJtZGAsIAogIDIuIHdyaXRlIHlvdXIgbmFtZSBhbmQgSUQgYW5kIHRoZSBjb250ZW50cywgCiAgMy4gcnVuIGVhY2ggY29kZSBibG9jaywgCiAgNC4gcHJldmlldyB0byBjcmVhdGUgYGEzXzEyMzQ1Ni5uYi5odG1sYCwKICA1LiBzdWJtaXQgIGBhM18xMjM0NTYubmIuaHRtbGAgdG8gTW9vZGxlLgoKMS4gQ2hvb3NlIGEgZGF0YSB3aXRoIGF0IGxlYXN0IHR3byBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgYW5kIGF0IGxlYXN0IHR3byBudW1lcmljYWwgdmFyaWFibGVzLgoKICAgIC0gSW5mb3JtYXRpb24gb2YgdGhlIGRhdGE6IE5hbWUsIEluZGljYXRvciwgRGVzY3JpcHRpb24sIFNvdXJjZSwgZXRjLgogICAgLSBFeHBsYWluIHdoeSB5b3UgY2hvc2UgdGhlIGluZGljYXRvcgogICAgLSBMaXN0IHF1ZXN0aW9ucyB5b3Ugd2FudCB0byBzdHVkeQoKLS0tCgoyLiBFeHBsb3JlIHRoZSBkYXRhIHVzaW5nIHZpc3VhbGl6YXRpb24gdXNpbmcgYGdncGxvdDJgCgogICAgLSBDcmVhdGUgdmFyaW91cyBjaGFydHMKICAgIC0gQ3JlYXRlIGF0IGxlYXN0IG9uZSBjaGFydCB3aXRoIGF0IGxlYXN0IHR3byBjYXRlZ29jaWFsIHZhcmlhYmxlcyBhbmQgYXQgbGVhc3Qgb25lIG51bWVyaWNhbCB2YXJpYWJsZS4KICAgIC0gQ3JlYXRlIGF0IGxlYXN0IG9uZSBjaGFydCB3aXRoIGF0IGxlYXN0IHR3byBudW1lcmljYWwgdmFyaWFibGVzIGFuZCBhdCBsZWFzdCBvbmUgY2F0ZWdvcmljYWwgdmFyaWFibGUuCgozLiBPYnNlcnZhdGlvbnMgYmFzZWQgb24geW91ciBkYXRhIHZpc3VhbGl6YXRpb24sIGFuZCBkaWZmaWN1bHRpZXMgYW5kIHF1ZXN0aW9ucyBlbmNvdW50ZXJlZCBpZiBhbnkuCgoqKkR1ZToqKiAyMDIzLTAxLTIzIDIzOjU5OjAwLiBTdWJtaXQgeW91ciBSIE5vdGVib29rIGZpbGUgaW4gTW9vZGxlIChUaGUgRm91cnRoIEFzc2lnbm1lbnQpLiBEdWUgb24gTW9uZGF5IQoKCgoK